最小化应用程序窗体会导致模态窗体关闭,但不会关闭消息框。

4
如果我在模态对话框打开时以编程方式最小化应用程序的窗体,则该模态对话框将关闭。
但是,如果我在MessageBox打开时以编程方式最小化应用程序的窗体,则不会关闭MessageBox(即当我将应用程序恢复为正常窗口状态时,MessageBox仍然显示)。
以下是演示差异的示例代码:
    public partial class Form1 : Form
    {
        // ... 

        private void showMessageBoxBtn_Click(object sender, EventArgs e)
        {
            timer1.Start();

            // This MessageBox does *not* get closed when the WindowState of Form1 is set to minimized in timer1_Tick
            MessageBox.Show(this, "MessageBox");
        }

        private void formShowDialogBtn_Click(object sender, EventArgs e)
        {
            timer1.Start();

            // This form gets closed when the WindowState of Form1 is set to minimized in timer1_Tick
            Form2 form2 = new Form2();
            form2.ShowDialog(); 
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Minimized;
            timer1.Stop();
        }
    }

问题:

有没有办法让表单的行为像消息框一样?


我无法在窗体最小化并打开消息框时恢复窗口状态。您确定在实际应用程序中有这段代码吗? - Sergey Berezovskiy
这是我看到的:http://www.screencast.com/t/ktmpVDovma - Matt Smith
1
@lazyberezovsky,就像你一样,我无法恢复MessageBox。 - Żubrówka
@Quintium,DialogResult 是 Cancel,而 CloseReason 是 None。 - Matt Smith
感谢大家的反馈,我非常感激大家投入的时间来研究这个问题。 - Matt Smith
显示剩余7条评论
5个回答

9
你所看到的是Winforms中为应对对话框可用性问题而内置的应对措施的副作用,而MessageBox()函数并没有这样的应对措施。这些措施在Windows 98上可能更加相关,因为它最初是Winforms的一个重要目标操作系统,但是我记不清了。
一个重要的可用性问题就是当你显示一个对话框并将其最小化时会发生什么。对话框将禁用应用程序中所有其他窗口,因此您无法再激活它们。对话框应该将其ShowInTaskbar属性设置为false。现在用户有一个问题,就是没有简单的方法回到对话框。没有可以点击的东西。
Winforms通过自动关闭对话框来避免这种陷阱。正如你所看到的,MessageBox并没有这样做。它也无法合理地这样做,因为它没有好的方式返回“对话框已取消”的状态码。
值得注意的是,这个陷阱仍然部分存在。在我的Win8机器上,我可以点击禁用的窗体的任务栏按钮,并让它移回前台。但这会激活禁用的窗体而不是消息框。这是一个主要的用户界面错误,如果消息框在那个窗体后面,那就很糟糕了。
所以,回答你的问题:不是一个错误,而是一个特性。

非常好的答案(一如既往)。谢谢。在进行更多测试时,我惊讶地发现模态WPF表单没有相同的功能 - 它们不会在应用程序最小化时关闭。 - Matt Smith

1
首先,在方法范围之外声明Form2表单变量,以便可以从timer1_tick方法中访问。然后,在Timer滴答时,最小化主窗体,但显示模态对话框,然后将其最小化。
请尝试这样做:
Form2 form2;

private void timer1_Tick(object sender, EventArgs e)
{
    WindowState = FormWindowState.Minimized;
    form2.Show();
    form2.WindowState = FormWindowState.Minimized;
    timer1.Stop();
}

@MattSmith,你的问题是:“有没有办法使窗体的行为像消息框一样?”这就是我的答案。它可以在你单击任务栏中的主窗体后将对话框显示为模态。很抱歉,也许我错过了问题的要点。 - Alex Filipovici
1
抱歉,我误读了你的回答并过于草率地将其驳回。这很有趣。我真的不明白它为什么有效(你明白吗)。对于我的实际目的,它不太适用,因为我不希望Form2知道主应用程序何时被最小化(即最小化应用程序的代码不应该知道form2)。话虽如此,它确实似乎与MessageBox的行为相匹配。 - Matt Smith

0

Matt,

尝试更改:

form2.ShowDialog();

form2.Show(this);

这是您要寻找的行为吗?


不,我需要一个模态对话框。 - Matt Smith

0
你可以尝试这样做:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication37
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetParent(IntPtr hWnd);

        Form2 form2 = null;
        IntPtr parent = IntPtr.Zero;

        public Form1()
        {
            InitializeComponent();
        }

        private void formShowDialogBtn_Click(object sender, EventArgs e)
        {
            timer1.Start();

            // This form gets closed when the WindowState of Form1 is set to minimized in timer1_Tick
            form2 = new Form2();
            form2.ShowDialog();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            WindowState = FormWindowState.Minimized;
            timer1.Stop();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.parent = GetParent(form2.Handle);
                SetParent(form2.Handle, IntPtr.Zero);
                form2.Hide();
            }
            else
            {
                SetParent(form2.Handle, this.parent);
                form2.ShowDialog();
            }
        }
    }
}

请注意,这种方法有点像是一个黑客技巧,我对后果并不完全确定。接受批评 :)

重新显示它可能会有点奏效。但是,我不想要求我的父窗体知道所有子窗体(或者让它们注册)。此外,对话框必须意识到它们可以以这种方式使用:例如,对话框的位置需要被记住,因为如果用户移动了对话框,第二次显示时位置就不同了。谢谢你的建议。 - Matt Smith

0

如果你设置了

Visible = true;

在以编程方式最小化所有者窗体后,模态窗体不会被操作系统关闭。
因此,
ownerForm.WindowState = FormWindowState.Minimized;

将关闭模态表单。但是

ownerForm.WindowState = FormWindowState.Minimized;
modalForm.Visible = true;

不会杀死它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接