【问题标题】:Main window disappears behind other application's windows after a sub window uses ShowDialog on a third window子窗口在第三个窗口上使用 ShowDialog 后,主窗口消失在其他应用程序的窗口后面
【发布时间】:2012-10-23 22:56:30
【问题描述】:

我在 WPF 应用程序中注意到了这种非常奇怪的行为。

我有一个MainWindow,使用来自App.OnStartupShow() 显示。说MainWindow可以打开一个(非模态)SubWindow,也可以使用Show()SubWindowOwner 设置为MainWindow

SubWindow 关闭时,MainWindow 再次可见(很好)。

使用ShowDialog()Owner 设置为SubWindow),某些操作可能会导致SubWindow 打开第三个窗口作为模式对话框。当该模态对话框在SubWindow 的生命周期内至少打开和关闭一次时,就会发生奇怪的事情。

关闭SubWindow 后,MainWindow 不会出现。取而代之的是, MainWindow 后面的任何随机窗口都会进入视野。谁能向我解释为什么会发生这种情况,以及如何解决它?

模态对话框是使用ShowDialog()显示的普通Window,还是使用MessageBox.Show()显示的消息框没有区别。


这里有一些最小代码来重现这个。在 Visual Studio 中创建一个新的 WPF 应用程序,并将其粘贴到预先生成的 MainWindow.xaml.cs 中

然后,按键盘上的一个键仅打开一个窗口,然后将其关闭,行为符合预期。按两个键,同时关闭,然后第一个窗口在 Visual Studio 后面(大概)。

public MainWindow()
{
    InitializeComponent();
    this.PreviewKeyDown += (sender, e) =>
    {
        if (this.Owner is MainWindow)
        {
            // we're the SubWindow

            MessageBox.Show("I am a modal dialog");

            // code below produces the exact same behavior as the message box

            //var dialog = new MainWindow();
            //dialog.Owner = this;
            //dialog.ShowDialog();
        }
        else
        {
            // we're the initial MainWindow created by App.
            var subWindow = new MainWindow();
            subWindow.Owner = this;
            subWindow.Show();
        }
    };
}

【问题讨论】:

  • 很好的问题。并且说得好。谢谢。

标签: c# wpf dialog window modal-dialog


【解决方案1】:

这是一个非常烦人的 WPF 错误,我从未在代码中找到导致它的缺陷,但在处理聚焦的源代码中存在大量“必须弄清楚”的 cmets。只是一种解决方法,一种不太理想的解决方法,您可以通过在窗口关闭时将焦点明确地赋予所有者来解决它。将此代码复制/粘贴到您的 SubWindow 类中;

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e) {
        base.OnClosing(e);
        if (!e.Cancel && this.Owner != null) this.Owner.Focus();
    }

【讨论】:

  • 值得我们在大约 5 年前工作的一个普通 WinForms (.NET 2) 应用程序中看到这个错误。我今天刚刚在一个新项目(.NET 4.5)中再次遇到它。我似乎记得这个错误取决于 Show() 嵌套 2 层或更多。看起来其他人也遇到过(herehere);如果我记得我们使用了@Hans 建议的解决方法。
  • 只是让您知道,您的代码会导致无限循环。我只能想象base.OnClosing 是一个虚函数,它在你调用的方法中实现,因此调用它自己。
  • 另一件事,处理Closing 事件并不能解决我的问题——我需要处理Closed 事件。
  • AFAIK Window.Closing 事件在覆盖之后触发,因此可以在之后设置 e.Cancel 以保持窗口打开但所有者仍然专注。使用 Closed 是一种可能的解决方法,但在某些情况下并不能避免问题:(
  • 在我的系统上 - .Net 4.6.1,Win 7,这在大约 98-99% 的时间里都有效。不幸的是,1% 的失败使它不适合生产代码。
【解决方案2】:

仅在隐藏窗口时遇到同样的问题。在这种情况下,我看不到有与 Closing 等效的事件,但无论如何这有效:

        if (Owner != null) Owner.Focus();
        Hide();

【讨论】:

    【解决方案3】:

    this.Owner.Focus();对我不起作用它仍然会转到后面的窗口我不得不玩一点并尝试使用 TopMost,TopMost 的问题是我需要在关闭后将其返回为 false。我同时使用了 OnClosing 和 OnClosed 事件。

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {
        base.OnClosing(e);
        if (!e.Cancel && this.Owner != null) this.Owner.TopMost = true;
    }
    
    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        if (this.Owner != null)
        {
            this.Owner.TopMost = false;
        }
    }
    

    【讨论】:

      【解决方案4】:

      我在 WinFoms (.NET 4.7+) 中遇到了同样的问题。我的解决方法是先关闭第一个对话框(调用其Close 方法),然后再显示第二个对话框。

      示例

      1. 主窗体打开FirstForm
      2. FirstForm 打开 SecondForm 并导致问题!

      解决方法

      FirstForm 中调用Close 方法将打开SecondForm

      // FirstForm.cs
      
      using(var secondForm = new SecondForm())
      {
          Close(); // <- this closes FirstForm instance
          secondForm.ShowDialog(owner: mainFormInstance);
      }
      

      HTH

      【讨论】:

        【解决方案5】:

        老问题,但我想我会分享对我的 C# WinForms 应用程序有用的东西,因为 Owner.Focus() 对我不起作用。

        这是来自 Daren 的 TopMost 修复的一个变体,但我发现我实际上不必将 TopMost 设置为 true 并返回。只需将其设置为自身即可防止父窗口消失在其他应用程序后面。

        protected override void OnClosing(CancelEventArgs e) {
            if (Owner != null)
                Owner.TopMost = Owner.TopMost;
            base.OnClosing(e);
        }
        

        【讨论】:

          猜你喜欢
          • 2011-10-01
          • 2015-09-25
          • 2011-11-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-17
          • 1970-01-01
          相关资源
          最近更新 更多