所有的WPF程序,都是由Application类实例创建,该类负责打开当前应用程序和窗体,并且决定如何关闭应用程序等。Application类的主要功能可以简单总结以下几点:
1、保持主线程
使用Application后,只要有窗体没有退出,则应用程序不会退出,他会重新定义出新的主窗体,只有所有的窗体都关闭,Appliction才决定是否退出应用程序。Application起到管理所有窗体的作用。看如下代码:
class Program { [STAThread()] static void Main(string[] args) { Application app = new Application(); Window win = new Window(); app.Run(win); } }
效果会开启一个应用程序,假如我们不使用Application ,代码如下:
class Program { [STAThread()] static void Main(string[] args) { Window win = new Window(); win.ShowDialog(); } }
感觉效果上,没有任何差别,但实际上,两个完全不一样,假如我们定义一个MainWindow的类,在这个类中放一个按钮,弹出另外一个窗体,效果会怎么样呢,看如下代码:
class Program { [STAThread()] static void Main(string[] args) { Application app = new Application(); Window win = new Window(); win.MouseDown += Win_MouseDown; win.ShowDialog(); app.Run(); } private static void Win_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { Window win = new Window(); win.Show(); } }
当我们关闭父窗体,应用程序并没有退出。如果将Application去掉,编写以下代码:
class Program { [STAThread()] static void Main(string[] args) { Window win = new Window(); win.MouseDown += Win_MouseDown; win.ShowDialog(); } private static void Win_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { Window win = new Window(); win.Show(); } }
我们关闭父窗体,则整个应用程序退出。
这说明Applicationn在有任何一个窗体存在的情况下,能保证软件的持续运行,保证主线程不退出。
2、启动xaml窗体
我们可以通过指定StartupUri ,来告诉Appliction如何启动窗体,其代码如下:
class Program { [STAThread()] static void Main(string[] args) { Application app = new Application(); app.StartupUri = new Uri("MainWindow.xaml",System.UriKind.Relative); app.Run(); } }
所以,我们在编写wpf应用程序的时候,会有一个App.xaml的文件,其就是Appliction的定义,看看其代码如下:
<Application x:Class="Ani.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Ani" StartupUri="MainWindow.xaml"> </Application>
也是通过指定StartupUri属性,启动窗体,那Application是如何启动的呢,我们可以在当前程序的obj目录下面,可以看到App.g.cs文件,打开里面的代码,可以看到如下代码:
public partial class App : System.Windows.Application { /// <summary> /// InitializeComponent /// </summary> [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] public void InitializeComponent() { #line 5 "..\..\App.xaml" this.StartupUri = new System.Uri("MainWindow.xaml", System.UriKind.Relative); #line default #line hidden } /// <summary> /// Application Entry Point. /// </summary> [System.STAThreadAttribute()] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] public static void Main() { Ani.App app = new Ani.App(); app.InitializeComponent(); app.Run(); } }
所以WPF应用程序会主动给我们创建一个主程序App.cs和一个App.xaml文件,但App.cs并没有对编辑器放开,我们只需要编辑App.xaml文件即可
3、应用程序的关闭方式
Application里面有一个ShudonwModel属性,这个属性是一个枚举对象,用于指定当前应用程序的关闭方式,其有三个选项。
OnLastWindowClos e | 默认行为,只要至少一个窗体存在,应用程序就保持运行状态,应用程序会根据窗体的开启循序,自动指定主窗体。 |
OnMainWindowClose | 这个是指,只要主窗体(最新开启)存在,应用程序才保持运行状态 |
OnExplicaitShutdown | 除非调用Appliction.Shutdown()方法,否则应用程序不会结束。 |
代码如下:
<Application x:Class="Ani.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Ani" StartupUri="MainWindow.xaml" ShutdownMode="OnLastWindowClose"> </Application>
4、应用程序的事件
Application提供了为数不多几个事件,但这几个事件非常有用。
4.1 Startup
这个事件在调用Appliction.Run()方法之前,并且在主窗体显示之前发生,可以使用这个事件读取当前应用程序的命令行参数,而且还示意使用该事件指定StartupUri 属性
4.2 Exit
事件发生在应用程序关闭时(不管是什么原因关闭),并在Run()方法返回之前发生,但此时已经不能取消关闭,但是可以通过Run()方法重新启动程序。
4.3 SessionEnding
该事件在window对话结束时发生,例如,当用户关闭或者注销计算机时,我们来确定是否关闭应用程序,我们可以设置SessionEndingEventArgsCancel属性设置为true来取消关闭应用程序。否则,当事件处理结束后,WPF会调用Application.Shutdown()方法关闭事件。
4.4 Activated
激活当前应用程序的时候调用,当从另外一个应用程序切换到当前应用程序的时候调用,当第一次显示窗体的时候调用
4.5 Deactived
当取消激活应用程序中的窗体的时候,触发该事件。当切换到另外一个应用程序时,调用该事件。
4.6 DispatcherUnhandledException
当应用程序中的任何位置,只要发生未处理的异常,就会发生该事件,使用该事件来记录重要错误。
5、处理命令行参数
为了处理命令行参数,需要响应Application.Startup事件。命令行参数以参数通过StartupEventArgs.Args属性作为字符串数组提供。
public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { if (e.Args.Length > 0) { foreach (var arg in e.Args) { Console.WriteLine(arg); } } } }
6、负责窗体之间的交互
我们可以通过Application的current属性,获取当前的Appliction,也可以通过Application的MainWindow属性,获取当前的主窗体,所以,可以通过Application访问当前的Application里面的数据,同时可以访问主窗体的数据。我们可以将一些全局信息,定义在Application中,那么应用程序在任意位置都可以访问,实现所有窗体互相交互,如下代码:
public partial class App : Application { public List<string> Globals = new List<string>(); private void Application_Startup(object sender, StartupEventArgs e) { ((App)Application.Current).Globals.Add("hello"); } }