我有
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的窗口的孩子?
答案 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
设置正确,并且您已设置MainWindow
到Application.ShutdownMode
值。通过这种方式,你可以完全明确WPF关于你想要的确切行为,即使你做了一些奇怪的事情,比如在{{之前创建一个ShutdownMode.OnMainWindowClose
对象,它也没有机会搞乱它。 1}}对象被创建。 :)