【问题标题】:winform ShowDialog(this) still failwinform ShowDialog(this) 仍然失败
【发布时间】:2015-10-27 04:25:17
【问题描述】:

我已经知道使用 ShowDialog() 会导致表单落后于其父表单。所以我在寻找解决方案。

很多人说解决方法是将父表单作为参数传递给子表单。

类似的东西。

using(Form f = new Form1())
{
     f.ShowDialog(this);// while the 'this' is the parent form calling
}

但此代码仍然失败。 这就是场景。

打开显示对话框的子窗体,然后当子窗体窗口仍处于活动状态时,单击显示桌面(或按 Window+D),然后打开其他应用程序。 打开应用程序后将其最小化或关闭。现在在您关闭或最小化其他应用程序之后。

现在子表单已经在父表单后面了。现在您应该按 alt+tab 或从任务栏单击它以再次正常工作。

我将不胜感激。

【问题讨论】:

  • 为什么不改用 Show 并将 Dialog 设置为最顶层??
  • f.ShowDialog();怎么样
  • f.TopMost = true;?
  • 不,我不能将 TopMost 设置为 true,因为有时它们是多任务处理,打开浏览器或其他应用程序

标签: c# forms winforms showdialog


【解决方案1】:

好问题。似乎子对话框是可见的,并且按下了Windows+D,父窗体忽略了请求(或者操作系统可能阻止向父窗体发送最小化请求,因为它有一个活动的模式对话框)。只是猜测。父窗体永远不会发送最小化消息。

您可以通过使用TOOLS -> Spy++ 观察到这一点,并注意在显示子对话框并按下Windows+D 时缺少发送到父窗口的窗口消息。收到的消息在橙色框中:

这意味着父窗体实际上从未被最小化。 Windows 停止绘制它,但打开另一个窗口会重新打开绘制。

所以使用WM_ACTIVATEAPP 作为参考点,强制父窗体最小化。这具有使子对话框不可见的副作用。然后监听SC_RESTORE 消息,并重新显示子对话框:

public class RestoreForm : Form {

    private const int SC_RESTORE = 0xF120;
    private const int WM_SYSCOMMAND = 0x0112;
    private const int WM_ACTIVATEAPP = 0x1C;

    public RestoreForm() {
        Button btn1 = new Button { Text = "ShowDialog(...)", AutoSize = true };
        btn1.Click += btn1_Click;

        Controls.Add(btn1);
    }

    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        if (f2 != null) {
            if (m.Msg == WM_ACTIVATEAPP) {
                if (f2.WindowState == FormWindowState.Minimized) {
                    this.WindowState = FormWindowState.Minimized;
                }
            }
            else if (m.Msg == WM_SYSCOMMAND) {
                var w = m.WParam.ToInt32();
                if (w == SC_RESTORE) {
                    f2.WindowState = FormWindowState.Normal;
                    //f2.Visible = true; // ignores staying on top of previous parent
                    f2.ShowDialog(this);
                }
            }
        }
    }

    Form f2 = null;
    void btn1_Click(object sender, EventArgs e) {
        f2 = new Form { Text = "Child" };
        f2.ShowDialog(this);
    }
}

【讨论】:

  • 谢谢,我刚看完。但由于某种原因,我刚刚迷路了。因为我现在还没有任何使用 Spy++ 和 windows 消息的经验。但我会试试看。
  • @zer09 windows 中的一切都在发送消息。您可以在此处(或在 MSDN 上)看到大量 WM_ 常量:pinvoke.net/default.aspx/Constants.WMSpy++ 只是一个收听这些消息的工具(以及一些其他实用程序)。
  • 哦,这么多,顺便说一句谢谢,现在我会尝试练习间谍++
  • +1 好点,虽然值得一提的是(因为你需要在f2中保留对子表单的引用),完整的代码应该附加到f2.FormClosed并完成关闭表单/将 f2 设置回 null。
【解决方案2】:

我最接近的解决方法是将 ShowInTaskbar 和 MinimizeBox 设置为 false。

实际上我可以在不禁用最小化框的情况下禁用 ShowInTaskbar,但是没有意义,允许用户最小化子窗体但他们仍然无法对父窗体执行任何操作。

【讨论】:

    猜你喜欢
    • 2015-12-04
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多