17

我有以下简单的 wpf 应用程序:

应用程序.xaml:

<Application x:Class="TestWpf2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>

应用程序.xaml.cs:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        var parentWindow = new Window();
        parentWindow.Show();

        var childWindow1 = new Window { Owner = parentWindow };
        childWindow1.Show();

        var childWindow2 = new Window { Owner = parentWindow };
        childWindow2.Show();
    }
}

该应用程序导致 3 个窗口出现在屏幕上。如果您运行应用程序并关闭两个子窗口,则父窗口将最小化到任务栏。如果您注释掉childWindow2.show()、运行应用程序并关闭单个子窗口,则父窗口不会最小化到任务栏。

我可以添加以下代码来解决这个问题:

childWindow1.Closing += delegate(object sender, CancelEventArgs ex)
{
    (sender as Window).Owner = null;
};

但我不想使用这样的黑客,我想了解为什么会出现这个问题。

为什么会这样?

4

3 回答 3

17

这是 WPF 未记录的功能(错误)

此错误已在 7 多年前向 Microsoft 报告。

非模态窗口顶部的模态对话框将主窗口向后发送。

WPF 团队最近审查了此问题,并且不会解决此问题,因为此时团队正在关注影响最多 WPF 开发人员的错误。

让我们看一下这个未记录的特性的行为。

它不会最小化,只是落后一个窗口(在调试模式下,在 Visual Studio 窗口后面)

证明步骤:

  • 运行此应用程序。

  • 最小化所有其他窗口(例如:visual studio 和所有其他窗口)。在屏幕上只保留这三个窗口。

  • 关闭两个孩子,父母仍处于Normal状态

测试此代码以进一步证明: StateChange不会触发。

        protected override void OnStartup(StartupEventArgs e)
        {
            var parentWindow = new Window() { Title = "Parent" };
            parentWindow.StateChanged += (sender, ep)=>
            {
                var state = ((Window)sender).WindowState;
            };
            parentWindow.Show();

            var childWindow1 = new Window { Owner = parentWindow, Title = "Child1" };
            childWindow1.Show();

            var childWindow2 = new Window { Owner = parentWindow, Title = "Child2" };
            childWindow2.Show();
        }

成为 TopMost 可以防止这种情况发生

如果父窗口是 TopMost,则不会发生这种情况。但在许多情况下,这可能不是一个选择。

parentWindow.Topmost = true;

解决方法

在 child2 关闭时激活父级。

childWindow2.Closed += (a, b) => { parentWindow.Activate(); };
于 2017-06-13T13:17:17.327 回答
3

这是因为一旦子窗口显示为所有者集,您就不能使用父窗口。只需在孩子在屏幕上时尝试访问父窗口,它不会让你明白我的意思。

如果您不指定所有者,则不会发生此行为。

于 2012-05-25T17:28:16.780 回答
1

我从来没有弄清楚是什么导致了这种情况发生!最后,我写了这段代码,在任何子窗口关闭后调用:

// App inherits from Application, and has a Window property called MainWindow
// and a List<Window> property called OpenWindows.
if (!App.OpenWindows.Any())
    App.ParentWindow.Activate();

因此,如果最后一个子窗口关闭(设为App.OpenWindows.Any()假),则激活父窗口。这不会导致闪烁(例如,主窗口最小化然后最大化。)

这不是最好的解决方案。我不会关闭这个问题,希望有人能解释为什么 WPF 有这个功能!

于 2012-11-20T12:09:39.573 回答