WPF App完全关注窗口关闭

时间:2010-06-29 19:24:16

标签: .net wpf

问题描述

如果我通过将窗口的所有者设置为父窗口而将非模态窗口设置为子窗口,然后在此子窗口中显示MessageBox,则在关闭子窗口时父窗口将失去焦点。如果Windows资源管理器或其他应用程序处于打开状态,此应用程序将获得焦点,我的主窗口将被隐藏。

这似乎是一个已知的问题,因为我在另一个newsgroups中看到了它,但我没有看到一个好的解决方案。在OnDeactivate中将所有者设置为null不是一个选项。在将MessageBox显示为null并在此之后重置之前设置所有者没有帮助。在OnClosed事件中将所有者设置为null也无济于事。

找到简单解决方案

如果您遇到与我所述相同的问题,请将以下代码放在所有子窗口的OnClosing中。

void  OnClosing(System.ComponentModel.CancelEventArgs e)
  base.OnClosing(e);
  if (null != Owner) {
         Owner.Activate();
  }
  // ....

可以跟随任何进一步的处理逻辑,甚至可以容忍打开MessageBox。

示例-代码

这个问题似乎比我想象的要大得多。如果将打开消息框并关闭子窗口,则以下示例将删除父窗口的焦点(将代码复制到窗口的已加载事件处理程序中)。

Window firstChildWindow = new Window() {
    Title = "Floating Window", Width = 100, Height = 70
};
firstChildWindow.Owner = Window.GetWindow(this);

Button button = new Button() { Content="MessageBox"};
button.Click += delegate { 
    MessageBox.Show("Klicking her breaks the focus-chain."); };
firstChildWindow.Content = button;
firstChildWindow.Show();

此示例也打破了焦点链:

Window firstChildWindow = new Window() {
    Title = "Floating Window", Width = 100, Height = 70
};
firstChildWindow.Owner = Window.GetWindow(this);
firstChildWindow.Show();

Window secondChildWindow = new Window() { 
    Title="Second Window",Width=100,Height=70};
secondChildWindow.Content = new TextBlock() { 
    Text="SecondWindow"};
secondChildWindow.Owner = firstChildWindow;
secondChildWindow.Show();

是否有人解决此问题。关于在关闭之后触发给予父母关注的黑客攻击,使用Dispatcher或DispachterTimer,或者也许它可以在关闭时手动将焦点强制给父母,但这一切在我看来都是非常不洁净的(如果正如我在当前的应用程序中那样,父母拥有更多活动拥有的窗口。

没有人知道这个问题的解决方案吗?

资源

MSDN Description(请参阅非模态窗口的备注,调用Show())

Same problem on msdn forums without appropriate solution

另请参阅:Instable focus of WPF apps

8 个答案:

答案 0 :(得分:24)

这里最有可能发生的事情是你有两个独立的顶级窗口并关闭其中一个窗口。这有时会导致焦点转移到另一个应用程序。

如果一个窗口拥有第二个窗口,而后者拥有第三个窗口,则也会发生这种情况。在Win32 API中可能存在BUG,但它永远和我们在一起,所以运气好了。

解决方法是在孙子的Closing事件中手动将焦点移回到子节点。但在这种情况下,孙子是一个消息框,所以你不能这样做。最简单的方法是将messagebox保存到父级。下一个最简单的方法是制作自己的消息框控件。

答案 1 :(得分:21)

这是一个非常烦人的错误,最常见的解决方案是:

Me.Owner.FocusWindow_Unloaded事件中致电Window_Closing

但是仍然不能100%工作,在正确恢复焦点之前,你仍会看到背景窗口闪烁到前景(非常简短)。

我发现了一种效果更好的方法:

Me.Owner.Activate之前(或在Me.Close事件中)致电_Closing

答案 2 :(得分:2)

也许我在这件事上已经很晚了 @HCL通过将 MessageBox.show()选项参数设置为 MessageBoxOptions.None ,可以更轻松地解决此问题。

干杯...

答案 3 :(得分:0)

可以编写自己的消息框,您可以将其实现为浮动,在显示时禁用整个屏幕。

你检查了caliburn mvvm frameork示例,有一个很好的messagebox实现服务。

答案 4 :(得分:0)

所有权与哪个窗口激活无关。要查看此内容,请将第二个窗口的所有者更改为顶部窗口并运行该程序。请注意,没有任何变化所有权与“如果窗口最小化,其他窗口需要最小化”有关。所以你很难使用自定义激活码。

答案 5 :(得分:0)

Johsua的.Activate(见上文)解决方案适用于各种窗口类型。 至少它为我做了诀窍。

答案 6 :(得分:0)

我有类似的问题。我有一个主窗口,其余的子窗口通过Owner属性分配给该窗口。如果主窗口有两个或两个以上的孩子,关闭第二个孩子后,app会失去焦点。我在关闭之前使用了与child.Owner = null的技巧,但随后我的下一个子窗口失去了焦点。我通过让所有孩子处理它并在关闭孩子之前将焦点设置到最后一个孩子。这是代码示例:

private void OnClosing(object sender, CancelEventArgs cancelEventArgs)
        {
            var childWindows = (sender as Window).Owner.OwnedWindows;
            if (childWindows.Count - 2 >= 0)
                childWindows[childWindows.Count - 2].Focus();
            else
            {
                (sender as Window).Owner.Focus();
            }
            (sender as Window).Owner = null;
        }

答案 7 :(得分:0)

2020年,仍然有麻烦...

Wpf的解决方法:

    public ContactsWindow()
    {
        InitializeComponent();

        Closing += ContactsWindow_Closing;
    }

    private void ContactsWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        Owner?.Activate();
    }

似乎对我有用,对任何新闻感兴趣