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

问题描述:

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

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

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

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

是该窗口中的“主”窗口?

让我们来定义关闭过程中OwningWindow(希望这个名字是不是在这方面载)窗口。我怎样才能确保显示的第一个窗口是OwningWindow?

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

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

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

是该窗口中的 “主” 窗口?

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

当然,如上面所讨论的,Application对象没有办法看到被创建之前它本身创建的窗口。一个例外:如果您将窗口传递给Run()方法,即使该窗口是在Application对象之前创建的,也可以成为MainWindow。如果所有的窗口都是在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对象之后创建,这与Application类正确注释的上述想法一致任何窗口创建和/或显示后它自己创建)。


恕我直言,最好的办法是不要混淆的方法。它无法正确处理在Application对象创建之前显示的窗口。所以,不要这样做。确保在创建Application之后,才会创建全部。如果您关闭的具体行为与默认的ShutdownMode.OnLastWindowClose行为不同,那么这应该很简单,可以实现。

这可能是因为刚刚ShutdownMode属性设置为别的东西一样简单。例如,ShutdownMode.OnMainWindowClose。在这种情况下,您当然需要确保某个窗口是主窗口,否则该进程将不会退出。您可以明确,甚至通过传递窗口参考Run()方法在创建了使用默认行为做到这一点(即创建主窗口的第一个窗口,但Application对象被创建之后),通过设置MainWindow财产Application对象之前的所有窗口。


让我们来定义关闭过程中OwningWindow(希望这个名字是不是在这方面载)窗口。我怎样才能确保显示的第一个窗口是OwningWindow?

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

首先, “拥有窗口” 实际上是MainWindow。但是,默认情况下,Application.Run()方法仅在所有窗口(它已知)已关闭时才会返回。只有通过隐藏Application方法中的一些窗口,才能看到某个“拥有窗口”负责关闭程序(在默认的ShutdownMode方案中)。实际上,如果你想要的只是在某些特定的窗口本身关闭时关闭程序,那么正确的方法是确保MainWindow设置正确,并且已将Application.ShutdownMode设置为值为ShutdownMode.OnMainWindowClose。这样一来,你正在使用WPF完全明确一下你想要的确切行为,它不会有机会搞砸了,即使你做一些怪异像创建Application对象之前创建一个Window对象。:)

+0

Ah默认ShutdownMode解释了为什么当我通过窗口它仍然有相同的行为(当我期望我通过的窗口关闭应用程序退出时)。感谢您的详细回复! – user815512

+0

继续这个主题,让我们说,作为我的应用程序启动的一部分,我想显示一个窗口,然后在关闭之后显示另一个窗口。我可以通过不同的窗口调用app.Run()两次来做到这一点吗?或者是一些涉及Application类的状态,将禁止这个? – user815512

+0

@ user815512:我不知道我的头顶。我希望你能够多次调用'Run()'。但是我也认为如果这是你的场景,你最好将'ShutdownMode'设置为'OnExplicitShutdown',这样你的代码就可以完全控制。或者,使用'OnMainWindowClose',只要您在关闭第一个窗口并设置MainWindow属性之前创建第二个窗口,则关闭第一个窗口不应导致应用程序退出。基本上:为什么要问麻烦? WPF允许你完全控制关闭逻辑,所以你也可以。 –