前言html
I should know how I am supposed to exit my application when the user clicks on the Exit menu item from the File menu. 或者点击window右上角的X退出应用。python
可是退出应用程序时,应该考虑到哪些点呢?程序员
(1)有人认为在关闭应用前,应该触发一个确认窗口,指示用户是否确认退出,由于if there are jobs running, the force exit will cause damages, so we better to let them informed in the confirmation dialog。express
(2)有人认为太多的确认是一件很是糟糕的事情。事实上,有人花了点击打开文件菜单,一直向下移动到文件菜单的底部,而后单击退出,几乎确认他们再也不但愿使用该应用程序。windows
其实就我来看,上面两类观点都有道理,关键是要适合本身的状况。(This is better to be designed case by case,此话老套而不过期)app
如何根据实际状况进行权衡,就是本文要讨论的如何优雅地退出应用程序的问题,只不过这里只针对WPF应用而言。post
正文测试
做为一个程序员,咱们先关注下实现exit application的技术。this
- 首先,咱们可能想到使用:
Application.Current.Shutdown();
(注:Application.Current.Shutdown(); 只能从建立Application对象的线程调用,即一般是主线程)url
我作过测试,在MainWindow中,我触发了其余几个windows,而后在MainWindow的window_closed事件中,我添加了该代码,全部的窗口都消失了,但后台程序仍旧在运行。
这是为何呢?
其实,全部其余owned窗口会被关闭,但你必须确保声明全部权。若是你有一个正在运行的窗口,而后打开另外一个窗口但还没有显示,则在关闭活动窗口后,隐藏的窗口将强制应用程序继续运行。除非你经过其余方式(任务管理器等)关闭该窗口,不然将会有潜在的内存泄漏。
另外值得注意的是:Application.Current.Shutdown();是不可逆转的,它一般用于强制应用程序关闭,例如用户注销或关闭Windows时。Instead, 在主窗口中调用this.close(), 这与按“ALT-F4”或窗口上的关闭[x]按钮做用相同。这将致使全部其余全部的窗口关闭,并将最终调用Application.Current.Shutdown();只要关闭动做未被取消。可参阅关闭窗口的MSDN文档。
另外,因为this.close()能够取消,你能够在关闭事件处理程序中放入保存更改确认对话框。只须要构建<Window Closing =“...”>的事件处理程序,并相应地更改e.Cancel的值(true or false)。
- 其次,若是你真的须要关闭应用程序,你也可使用Environment.Exit(),但它并不优雅(更像是结束进程):
Environment.Exit(0)
Environment.Exit()至少须要一个参数,一个退出代码。若是你不关心退出代码,就像上面那么用。
Environment.Exit is definitely the right way to ensure shutdown of an application. With Application.Current.Shutdown you can easily end up with the application running on indefinitely if you have code that pushes itself back into the dispatcher. 意思就是说这绝对是确保关闭应用的正确方式。使用Application.Current.Shutdown,当你的代码中有回调自身的状况时,很容易出现程序无限运行的结果。
注:与Application.exit(0);同等效果。
代码实例:
MainWindow.xaml中windows部分详情以下:
1
2
3
4
5
6
7
8
9
|
<Window
xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d=
"http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc=
"http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local=
"clr-namespace:Application"
mc:Ignorable=
"d"
Title=
"Application"
Height=
"1050"
Width=
"1800"
Closing=
"Window_Closing"
Icon=
"Images/app_icon.png"
Loaded=
"Window_Loaded"
>
|
MainWindow.xaml.cs关键部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
// Any control that causes the Window.Closing even to trigger.
private
void
MenuItem_Exit_Click(
object
sender, RoutedEventArgs e)
{
this
.Close();
}
// Method to handle the Window.Closing event.
private
void
Window_Closing(
object
sender, System.ComponentModel.CancelEventArgs e)
{
try
{
MessageBoxResult msgBoxResult = MessageBox.Show(
"Do you really want to exit?"
,
"Exiting..."
, MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if
(msgBoxResult == MessageBoxResult.No)
{
e.Cancel =
true
;
return
;
}
else
{
var
jobState = XXX.GetJobState();
if
(jobState == finished || ...)
{
e.Cancel =
false
;
}
else
{
MessageBox.Show(
"Application is running job, please wait till finish. "
);
e.Cancel =
true
;
return
;
}
}
//to do something Uninitialize or ...
}
catch
(Exception ex)
{
XXX.LogError(appName, ex);
}
CloseChildWindows();
}
private
void
CloseChildWindows()
{
if
(pythonWindow !=
null
)
{
pythonWindow.Closed -= ChildWindowClosed;
pythonWindow.Close();
pythonWindow =
null
;
}
......
}
|
注:该部分一些方法或变量是模拟的。