WPF应用程序类和主窗口初始化

时间:2015-11-17 23:03:31

标签: c# wpf windows sta

我有

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();
}

如果我运行如图所示的代码并关闭任何窗口,它将关闭所有窗口。如果我切换到注释掉的内容,那么哪个窗口会导致所有窗口关闭(大部分时间是最后一个窗口)似乎是随机的。

应用程序如何决定哪个窗口会导致进程关闭?

该窗口是" main"窗口?

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

这最后一个问题是我的主要问题。我不想打开其他辅助窗口,让用户关闭主窗口,并让进程继续运行。或者我是否必须使后续窗口中的窗口成为我想成为OwningWindow的窗口的孩子?

1 个答案:

答案 0 :(得分:1)

  

应用程序如何决定哪个窗口会导致进程关闭?

默认情况下,当所有打开的窗口都已关闭时,Application类将退出Run()方法(因此此处为整个过程)。根据你的代码示例,似乎有一个皱纹:Application类不考虑在它自己创建之前打开的任何窗口。如果你没有告诉它任何窗口(即通过传递对Run()方法的引用),那么任何窗口关闭都会导致Run()方法退出,因为Application 看到窗口的关闭,但认为过程中没有窗口。

  

那个窗口是“主”窗口吗?

默认情况下,“main”窗口是AppDomain中要实例化的第一个窗口。您可以通过设置Application对象的MainWindow属性随时覆盖此项。

当然,如上所述,Application对象无法在创建窗口之前查看窗口。例外:如果您将窗口传递给Run()方法,即使窗口是在MainWindow对象之前创建的,也可以成为Application。如果所有窗口都是在Application之前创建的,并且您没有将对这些窗口的引用传递给Run()方法,那么根本就没有主窗口。


如果要确定性地指定单个窗口以使窗口关闭时进程退出,则可以选择将其传递给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,所以在没有做任何其他事情的情况下,程序应该关闭,直到最后一个窗口关闭。这只是因为类似乎没有注意到在实例化之前发生的窗口打开(它显然会对窗口的实际创建做出反应,而不是在启动时搜索进程打开窗口)。


显然,在调用Application.Run()之前创建窗口会混淆方法;它似乎认为如果关闭任何窗户仍然没有打开。如果你传递给其中一个窗口的引用,它将不会返回,直到该窗口关闭,该窗口是它“知道”的唯一窗口;忽略任何其他窗口的关闭,因为它知道的一个窗口仍然是打开的。

(对于它的价值,在我的测试中,程序不会在所有窗口关闭之前退出,在它们都是在Application对象之后创建的场景中。这与上述{a}的观点是一致的。 {1}}类正确地记录了在创建它之后创建和/或显示的任何窗口。


恕我直言,最好的方法是不要混淆方法。它无法正确处理在创建Application对象之前显示的窗口。所以,不要这样做。确保在创建Application后创建所有的窗口。如果您具有与默认Application行为不同的特定关闭行为,那么这应该足够简单以实现。

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


  

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

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

首先,“拥有窗口”实际上是Application。但是,默认情况下,MainWindow方法仅在所有窗口(它知道)已关闭时返回。只有通过隐藏Application.Run()方法中的某些窗口,似乎某些“拥有窗口”负责关闭程序(在默认的Application方案中)。

实际上,如果您想要的只是在某个特定窗口本身关闭时关闭程序,正确的方法是确保ShutdownMode设置正确,并且您已设置MainWindowApplication.ShutdownMode值。通过这种方式,你可以完全明确WPF关于你想要的确切行为,即使你做了一些奇怪的事情,比如在{{之前创建一个ShutdownMode.OnMainWindowClose对象,它也没有机会搞乱它。 1}}对象被创建。 :)