WPF 应用程序 class 和主要 window 初始化

WPF Application class and main window initialization

我有

public static int WindowCounter = 0;

[STAThread]
public static void Main()
{
    ShowBeforeApplicationCreation();
    //ShowAfterApplicationCreation();
}

public static void ShowBeforeApplicationCreation()
{
    ShowWindow();
    ShowWindow();
    ShowWindow();
    var app = new Application();
    app.Run();
}

public static void ShowAfterApplicationCreation()
{
    var app = new Application();
    ShowWindow();
    ShowWindow();
    ShowWindow();
    app.Run();
}

public static void ShowWindow()
{
    var window = new Window { Title = string.format("Title{0}", WindowCounter++) };
    window.Show();
}

如果我 运行 如图所示的代码并关闭任何 windows,它将关闭所有 windows。如果我切换到注释掉的内容,那么 window 将导致所有 windows 关闭似乎是随机的(大多数时候它是最后一个)。

应用程序如何决定哪个 window 将导致进程关闭?

那个window是"main"window吗?

让我们将关闭进程的 window 定义为 OwningWindow(希望该名称在此上下文中不会过载)。如何确保显示的第一个 window 是 OwningWindow?

最后一个问题是我的主要问题。我不想打开其他辅助 windows,让用户关闭主要的,并让进程保持 运行ning。或者我是否必须使 window 的后续 windows children 我想成为 OwningWindow?

How is the Application deciding which window will cause the process to close?

默认情况下,Application class 将在所有打开的 windows 已关闭时退出 Run() 方法(以及此处的整个过程)。但是,根据您的代码示例,似乎存在一个问题:Application class 不考虑在其本身创建之前打开的任何 windows。如果你不告诉它任何 window (即通过传递对 Run() 方法的引用),那么任何 window 关闭都会导致 Run() 方法退出,因为 Application class 确实 看到了 window 的闭包,但是认为没有 windows 在这个过程中。

Is that window the "main" window?

默认情况下,"main" window 是 AppDomain 中实例化的第一个 window。您可以随时通过设置 Application 对象的 MainWindow 属性 来覆盖它。

自然地,如上所述,Application 对象在它自己被创建之前无法看到 windows 被创建。一个例外:如果将 window 传递给 Run() 方法,即使 window 是在 Application 对象之前创建的,它也可以成为 MainWindow。如果所有 windows 都是在 Application 之前创建的,并且您没有将对任何 windows 的引用传递给 Run() 方法,那么就没有 main window 完全没有。


如果您想确定性地分配一个 window 以在 window 关闭时导致进程退出,一种选择是将其传递给 Application.Run() 方法。例如:

class Program
{
    public static int WindowCounter = 0;
    private static Window _firstWindow;

    [STAThread]
    public static void Main()
    {
        ShowBeforeApplicationCreation();
    }

    public static void ShowBeforeApplicationCreation()
    {
        ShowWindow();
        ShowWindow();
        ShowWindow();
        var app = new Application();
        app.Run(_firstWindow);
    }

    public static void ShowWindow()
    {
        var window = new Window { Title = string.Format("Title{0}", WindowCounter++) };
        window.Show();
        _firstWindow = _firstWindow ?? window;
    }
}

也就是说,默认的 Application.ShutdownMode 值是 ShutdownMode.OnLastWindowClose,所以如果不做任何其他事情,程序应该 不会 关闭直到最后一个 [=121] =] 关闭。只是因为class似乎没有注意到实例化之前发生的windows的打开(它显然是对window的实际创建做出反应,而不是搜索过程用于在启动时打开 windows)。


显然,在调用 Application.Run() 之前创建 windows 会混淆该方法;似乎认为没有 windows 仍然打开,如果有关闭的话。如果您将对 windows 之一的引用传递给它,它不会 return 直到 window 关闭,window 是唯一的 window 它"knows" 关于;任何其他 window 的关闭都将被忽略,因为它知道的那个 window 仍然打开。

(值得一提的是,在我的测试中,在所有 windows 对象都在 Application 对象之后创建的情况下,程序不会退出,直到所有 windows 都关闭。这与上面的想法 Application class 正确地记录了任何 windows 创建的 and/or 在它本身创建之后显示。


恕我直言,最好的方法是不要混淆方法。它无法正确处理在创建 Application 对象之前显示的 windows。所以,不要那样做。确保仅在创建 Application 之后才创建 windows 的 all。如果您有不同于默认 ShutdownMode.OnLastWindowClose 行为的特定关闭行为,那么应该很容易实现。

这可能就像将 ShutdownMode 属性 设置为其他内容一样简单。例如,ShutdownMode.OnMainWindowClose。在这种情况下,你当然需要确保somewindow是mainwindow,否则进程根本不会退出。您可以使用默认行为(即创建主 window 作为第一个 window,但在创建 Application 对象之后),通过设置 MainWindow 属性 显式,甚至通过传递 window 对 Run() 方法的引用,该方法在 Application 对象之前创建了所有 windows。


Let's define the window that closes the process as the OwningWindow (hopefully that name isn't overloaded in this context). How can I ensure that the first window shown is the OwningWindow?

从上面的讨论中,您大概可以自己回答这个问题。 :)

首先,"owning window"实际上是MainWindow。但是,默认情况下,当 all windows(它知道)已关闭时,Application.Run() 方法仅 returns。只是通过从 Application 方法中隐藏一些 windows,似乎一些 "owning window" 负责关闭程序(在默认的 ShutdownMode 场景中)。

实际上,如果您想要的只是在某些特定 window 本身关闭时关闭程序,正确的做法是确保 MainWindow 设置正确,并且您已将 Application.ShutdownMode 设置为 ShutdownMode.OnMainWindowClose 值。这样,您就可以通过 WPF 完全明确地了解您想要的确切行为,并且它不会有机会搞砸它,即使您做了一些奇怪的事情,比如在 [= 之前​​创建一个 Window 对象11=] 对象被创建。 :)