WPF系列之应用程序生命周期

简介:

摘要:

WPF是微软最新的图形用户界面技术,从2003年公之于众(当时开发代号Avalon),其革命性的创建软件的方式便引起了高度关注,特别是对于使用Windows Form和GDI开发的人员。时至今日使用WPF进行开发已经不是什么新鲜事,但我还是想写一点关于WPF的东西与不太了解WPF的朋友一起学习。OK,今天就从最基础的开始吧,我们一块看一下WPF应用程序的生命周期。

内容:

1.一个简单的WPF应用

2.WPF中的主窗体

3.Application的生命周期

4.单实例运行WPF应用

一、一个简单的WPF应用

WPF应用程序是一种包含Application对象的Windows进程,Application对象提供了生命周期服务,因此要了解WPF应用的生命周期我们就需要从Application开始。

首先我们建立一个WPF应用,在默认情况下我们运行这个应用程序。

 MainWindow

我们使用默认WPF Application创建了一个WPF应用,默认情况下我们什么都不做,点击运行就会看到上面的窗口。那么这背后Visual Studio为我们做了什么呢?我们知道在Winform中有一个Program.cs,其中定义了Main函数,程序从Main开始执行,那么WPF有没有类似的函数呢?我们的MainWindow又是在何处指定运行的?

我们可以看到VS为我们自动生成了一个App.xaml及其对应的隐藏文件App.xaml.cs。在App.xaml.cs中我们可以看到它没有创建任何类,更没有启动MainWindow,那么打开App.xaml呢?打开App.xaml文件代码如下:

复制代码
1 <Application x:Class="WPFLifeCycle.App"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 StartupUri="MainWindow.xaml" ShutdownMode="OnLastWindowClose">
5 <Application.Resources>
6
7 </Application.Resources>
8 </Application>
复制代码

  

在这里我们看到x:Class="WPFLifeCycle.App",事实上这样的代码等同于创建了一个名为App的Application对象。而根节点Application的StartupUri属性指定了启动的窗口(StartupUri="MainWindow.xaml"),这就相当于创建了一个MainWindow类型的对象,然后调用其Show()方法。此时可能会有朋友问,按理说这个程序应该有个Main函数啊,为何在此看不到Main呢?程序如何创建Application?

其实,这一切都归功于App.xaml文件的一个属性BuildAction

 BuildAction

BuildAction属性指定了程序生成的方式,默认为ApplicationDefinition。对于WPF程序来说,如果指定了BuildAction为ApplicationDefinition之后,WPF会自动创建 Main函数,并且自动检测Application定义文件,根据定义文件自动创建Application对象并启动它(当然它会根据StartupUri创建MainWindow并显示)。

既然如此我们将BuildAction设置为None试试,我们运行会发现抛出如下错误:

 AppNoMainExceptio

很明显这时我们需要Main函数作为我们的程序入口,我们不妨手动创建试试,此时我们创建一个Program.cs类,代码如下:

复制代码
 1 using System;
2 using System.Windows;
3
4 namespace WPFLifeCycle
5 {
6 static class Program
7 {
8 [STAThread]
9 static void Main()
10 {
11 Application App = new Application();
12 MainWindow mw = new MainWindow();
13 mw.Show();
14 App.Run();
15 }
16 }
17 }
复制代码

运行之后我们看到的效果和之前完全一样。换句话说App.xaml文件和我们上面代码起到的效果是相同的,事实上上面的xaml代码在编译时编译器也会做出同样的解析,这也是WPF设计的一个优点--很多东西我们都可以在XAML中实现而不需要编写过多的代码。

备注: App.xaml帮我们做的工作具体如下:

a.创建Application对象,并且设置其静态属性Current为当前对象

b.根据StartupUri创建并显示UI

c.设置Application的MainWindow属性(主窗口)

d.调用Application对象的Run方法,并保持一直运行直到应用关闭

二、WPF中的主窗口

我们知道在Winform中我们有"主窗体"概念,在WPF中我们也同样有"主窗口"。"主窗口"是一个"顶级窗口",它不包含或者不从属于其他窗口。默认情况下,创建了Application对象之后会设置Application对象的MainWindow属性为第一个窗口对象来作为程序的"主窗口"。当然,如果你愿意这个属性在程序运行的任何时刻都是可以修改的。

在Winform中我们知道,主窗体关闭之后整个应用程序生命周期就会结束,这里我们不妨试试在WPF中是否如此。首先在应用程中添加另一个Window对象OtherWindow,然后在MainWindow中放一个按钮,点击按钮显示OtherWindow。运行效果如下:

 TwoWindow

现在点击关闭MainWindow之后我们发现OtherWindow并未关闭,当然Application并未结束:

 OtherWindow

这是不是说明Application关闭同Winform不同呢(当然我们调用Application.Current.Exit()是可以退出应用的)?在WPF中Application的关闭模式同Winform确实不同,WPF中应用程序的关闭模式有三种,它由Application对象的ShutdownMode属性来决定

 ShutdownMode

它的枚举值如下:

枚举名称

枚举值

说明

OnLastWindowClose

0

当应用程序最后一个窗口关闭后则整个应用结束

OnMainWindowClose

1

当主窗口关闭后则应用程序结束

OnExplicitShutdown

2

只用通过调用Application.Current.Shutdown()才能结束应用程序

从上图我们也可以看到默认情况下ShutdownMode值是OnLastWindowClose,因此当MainWindow关闭后应用程序没有退出,如果要修改它可以将光标放到App.xaml中的XAML编辑窗口中,然后修改属性窗口中的ShutdownMode,也可以在XAML中或者程序中设置ShutdownMode属性。

三、Application的生命周期

下面我们看看Application的生命周期(引用网上一张图片)

 WPFLifeCycle

上图片描述WPF应用的生命周期,其中值得一提的是Run方法后会调用应用程的Starup事件,而"已激活"、"已停用"分别对应Activated和Deactivate事件。DispatcherUnhandledException用来将事件路由到正确位置的对象,包括未处理的异常,可以用它来处理程序其他部分未处理的异常或者一些操作(例如保存当前文档)。当关闭、注销或者重新启动时则会触发SessionEnding事件,SessionEnding事件中的SessionEndingCancelEventArgs的ReasonSessionEnding属性可以指示你是执行了注销还是关闭(这是一个枚举属性)。

四、单实例运行WPF应用

虽然上面我们简单介绍了WPF应用的生命周期,但是默认情况下我们可以打开一个应用程序多个实例,例如你双击一个exe多次。当然有些时候这么做会带来很多好处,但是有时我们又不希望这么做,要避免这个问题其实很简单,同WinForm中单实例运行一个应用是一样的,我们只需要在应用程序启动时创建一个"排他锁",修改App.xaml.cs如下:

复制代码
 1 using System;
2 using System.Windows;
3 using System.Threading;
4
5 namespace WPFLifeCycle
6 {
7 /// <summary>
8 /// Interaction logic for App.xaml
9 /// </summary>
10 public partial class App : Application
11 {
12 Mutex mutex=null;
13 protected override void OnStartup(StartupEventArgs e)
14 {
15 base.OnStartup(e);
16 bool createdNew = false;
17 mutex = new Mutex(true, "WPFLifeCycle",out createdNew);
18 if (!createdNew)
19 {
20 MessageBox.Show("程序正在运行中,无法启动另一个实例!", "系统提示", MessageBoxButton.OK, MessageBoxImage.Warning);
21 this.Shutdown();
22 }
23 }
24 }
25 }
复制代码

此时如果我们已经运行了WPFLifeCycle.exe,当再双击此应用则会给出提示:

SingletonRun

目录
相关文章
|
前端开发 Ubuntu Linux
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
随着跨平台越来越流行,.net core支持跨平台至今也有好几年的光景了。但是目前基于.net的跨平台,大多数还是在使用B/S架构的跨平台上;至于C/S架构,大部分人可能会选择QT进行开发,或者很早之前还有一款Mono可以支持.NET开发者进行开发跨平台应用。
1101 0
【.NET6+Avalonia】开发支持跨平台的仿WPF应用程序以及基于ubuntu系统的演示
|
3月前
|
C# 开发者 Windows
WPF 应用程序开发:一分钟入门
本文介绍 Windows Presentation Foundation (WPF),这是一种用于构建高质量、可缩放的 Windows 桌面应用程序的框架,支持 XAML 语言,方便 UI 设计与逻辑分离。文章涵盖 WPF 基础概念、代码示例,并深入探讨常见问题及解决方案,包括数据绑定、控件样式与模板、布局管理等方面,帮助开发者高效掌握 WPF 开发技巧。
170 65
|
4月前
|
前端开发 C# 开发者
WPF开发者必读:MVVM模式实战,轻松构建可维护的应用程序,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离关注点,提高了代码的可维护性和可扩展性。本文详细介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定与逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种模式,开发者可以更高效地构建桌面应用程序。希望本文能帮助你在WPF开发中更好地应用MVVM模式。
205 1
|
4月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
108 0
|
4月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
102 0
|
4月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
379 0
|
4月前
|
开发者 C# 自然语言处理
WPF开发者必读:掌握多语言应用程序开发秘籍,带你玩转WPF国际化支持!
【8月更文挑战第31天】随着全球化的加速,开发多语言应用程序成为趋势。WPF作为一种强大的图形界面技术,提供了优秀的国际化支持,包括资源文件存储、本地化处理及用户界面元素本地化。本文将介绍WPF国际化的实现方法,通过示例代码展示如何创建和绑定资源文件,并设置应用程序语言环境,帮助开发者轻松实现多语言应用开发,满足不同地区用户的需求。
80 0
|
4月前
|
开发者 C# UED
WPF多窗口应用程序开发秘籍:掌握窗口创建、通信与管理技巧,轻松实现高效多窗口协作!
【8月更文挑战第31天】在WPF应用开发中,多窗口设计能显著提升用户体验与工作效率。本文详述了创建新窗口的多种方法,包括直接实例化`Window`类、利用`Application.Current.MainWindow`及自定义方法。针对窗口间通信,介绍了`Messenger`类、`DataContext`共享及`Application`类的应用。此外,还探讨了布局控件与窗口管理技术,如`StackPanel`与`DockPanel`的使用,并提供了示例代码展示如何结合`Messenger`类实现窗口间的消息传递。总结了多窗口应用的设计要点,为开发者提供了实用指南。
267 0
|
4月前
|
C# 前端开发 UED
WPF数据验证实战:内置控件与自定义规则,带你玩转前端数据验证,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据验证是确保输入正确性的关键环节。前端验证能及时发现错误,提升用户体验和程序可靠性。本文对比了几种常用的WPF数据验证方法,并通过示例展示了如何使用内置验证控件(如`TextBox`)及自定义验证规则实现有效验证。内置控件结合`Validation`类可快速实现简单验证;自定义规则则提供了更灵活的复杂逻辑支持。希望本文能帮助开发者更好地进行WPF数据验证。
139 0
|
4月前
|
开发者 C# Windows
WPF布局大揭秘:掌握布局技巧,轻松创建响应式用户界面,让你的应用程序更上一层楼!
【8月更文挑战第31天】在现代软件开发中,响应式用户界面至关重要。WPF(Windows Presentation Foundation)作为.NET框架的一部分,提供了丰富的布局控件和机制,便于创建可自动调整的UI。本文介绍WPF布局的基础概念与实现方法,包括`StackPanel`、`DockPanel`、`Grid`等控件的使用,并通过示例代码展示如何构建响应式布局。了解这些技巧有助于开发者优化用户体验,适应不同设备和屏幕尺寸。
109 0