当前位置: 首页 > news >正文

WPF的窗口生命周期

WPF的窗口生命周期与WinForm很不一样。

WPF的应用程序和窗口模型基于更现代的框架,引入了XAML声明、路由事件、依赖属性等概念,其生命周期事件也更为丰富且与WinForm有显著区别。下面我将系统地为您介绍WPF应用程序和窗口的生命周期,帮助您深入理解。


1. WPF应用程序整体结构

WPF应用程序的入口点在 App.xaml 和其代码隐藏文件 App.xaml.cs 中定义。App 类继承自 System.Windows.Application,负责管理整个应用程序的生存期。

1.1 Application 对象的生命周期事件

Application 对象按以下顺序触发事件:

  1. Startup
    在应用程序启动后、Application对象初始化完成时发生。这是您通常处理命令行参数、设置初始主窗口的地方。
    示例:

    protected override void OnStartup(StartupEventArgs e)
    {base.OnStartup(e);// 处理命令行参数// 创建并显示主窗口MainWindow = new MainWindow();MainWindow.Show();
    }
    
  2. Activated
    当应用程序成为前台应用程序时发生(例如用户切换到该程序)。注意这是整个应用程序的激活,不是单个窗口。

  3. Deactivated
    当应用程序不再是前台应用程序时发生(例如用户切换到其他程序)。

  4. DispatcherUnhandledException
    当应用程序中发生未处理的异常时发生。您可以在其中记录异常并防止程序崩溃。

  5. SessionEnding
    当用户注销或关闭系统时发生。您可以在此时询问用户是否保存数据或取消关闭。

  6. Exit
    在应用程序关闭之前发生。您可以在此进行清理工作(如保存配置、释放资源)。

注意StartupExit 是最常用的两个事件,通常配合 ShutdownMode 属性控制应用程序何时退出。

1.2 Application 的 ShutdownMode

Application.ShutdownMode 决定应用程序何时自动退出,有三个选项:

  • OnLastWindowClose(默认):当最后一个窗口关闭时,应用程序退出。
  • OnMainWindowClose:当 Application.MainWindow 属性指定的窗口关闭时退出(不管其他窗口是否打开)。
  • OnExplicitShutdown:需要显式调用 Application.Shutdown() 才会退出。

您可以在 XAML 中设置:

<Application x:Class="MyApp.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="MainWindow.xaml"ShutdownMode="OnMainWindowClose">
</Application>

2. Window 对象的生命周期事件

一个 Window 对象从创建到关闭会经历一系列事件。注意,WPF窗口的事件顺序与WinForm不同,并且一些事件在WinForm中不存在(如 ContentRendered)。

2.1 窗口创建与初始化阶段

  1. 构造函数
    InitializeComponent() 方法解析XAML并构建可视化树。

  2. SourceInitialized
    当窗口的 HwndSource(底层窗口句柄)被创建时发生。此时窗口的句柄已可用,但尚未显示。通常用于高级Win32互操作。

  3. Loaded
    当窗口布局引擎完成测量和排列,且元素已添加到可视化树中但尚未呈现时发生。这是执行界面初始化(如绑定数据、设置默认焦点)的好时机。

  4. ContentRendered
    当窗口的内容(即整个可视化树)首次完成渲染后发生。注意,它会在每次内容重排后触发?实际上,它在第一次呈现后触发一次。可用于执行一些依赖渲染完成的操作。

2.2 窗口激活与失活阶段

  1. Activated
    当窗口成为前台窗口时发生。
    注意:如果窗口从未获得焦点(例如在后台启动),则不会触发此事件,直到用户点击它。

  2. Deactivated
    当窗口不再是前台窗口时发生。

2.3 窗口关闭阶段

  1. Closing
    当窗口即将关闭时发生(由用户点击关闭按钮、调用 Close() 或应用程序退出引起)。
    这是一个 可取消 的事件:您可以设置 CancelEventArgs.Cancel = true 来阻止窗口关闭。常用于提示用户保存更改。

  2. Closed
    当窗口已关闭(已从屏幕上移除)后发生。此时窗口资源已被释放,您可以进行最终清理(如注销事件、释放非托管资源)。

重要Closed 之后,窗口对象仍可访问(如属性),但 IsLoaded 变为 false,且无法再次显示。

2.4 其他事件

  • StateChanged:当窗口状态(Normal、Minimized、Maximized)改变时发生。
  • LocationChanged:当窗口位置改变时发生。
  • SizeChanged:当窗口大小改变时发生。

3. Application 与 Window 生命周期交互的典型流程

假设我们通过 Startup 事件手动创建并显示主窗口:

protected override void OnStartup(StartupEventArgs e)
{base.OnStartup(e);MainWindow = new MainWindow();MainWindow.Show(); // 窗口开始初始化
}

此时触发的事件顺序(假设ShutdownMode为默认的OnLastWindowClose):

序号 事件源 事件 说明
1 Application Startup 应用启动,准备创建窗口
2 Window 构造函数 MainWindow 实例化,InitializeComponent() 解析XAML
3 Window SourceInitialized 窗口句柄创建完成(通常用户无感)
4 Window Loaded 窗口布局完成,树已构建
5 Window ContentRendered 窗口内容首次渲染完成(此时用户看到窗口)
6 Window Activated 窗口成为前台窗口(如果启动时自动获得焦点)
7 Application Activated 整个应用成为前台
... (窗口运行中,可能多次切换焦点,触发Activated/Deactivated)
8 Window Closing 用户点击关闭按钮或调用Close()
9 Window Deactivated 如果窗口关闭时失去焦点(通常在Closing之后)
10 Window Closed 窗口已关闭,资源释放
11 Application Exit 应用程序退出(如果所有窗口都已关闭且ShutdownMode匹配)

注意:如果 ShutdownMode 设置为 OnMainWindowClose,则主窗口关闭后立即触发 Application.Exit(即使还有其他窗口打开)。如果还有窗口打开,它们会被强制关闭(不会触发Closing事件)。


4. 与 WinForm 的主要区别

方面 WinForm WPF
入口 Program.Main(),通常调用 Application.Run(form) App.xamlApp.xaml.csStartupUriOnStartup 创建窗口
窗口事件顺序 例如 Load 发生在窗口创建后、显示前;Shown 发生在第一次显示时 Loaded 在布局完成后;ContentRendered 在首次渲染后;没有 Shown
关闭逻辑 主窗体关闭默认退出 Application.Run 通过 ShutdownMode 控制,可自定义退出条件
应用程序对象 Application 类在 WinForms 中主要用于消息循环,生命周期简单 Application 功能强大,提供全局异常、会话结束等事件
多线程 需小心跨线程访问控件 同样要求UI线程操作,但提供了 Dispatcher 机制

重要差异点

  • WPF 的窗口是一个 控件容器,其初始化需要经过布局系统,因此 Loaded 发生在布局完成后,此时窗口尚未显示到屏幕;而 ContentRendered 则是真正显示后触发。
  • WPF 中没有直接等价于 WinForm 的 Shown 事件,通常用 ContentRendered 代替。
  • WinForm 的 FormClosing 事件对应 WPF 的 Closing,但 WPF 的 Closing 事件参数 CancelEventArgs 可用于取消关闭。
  • 应用程序退出:WinForms 通常在 Main 函数中调用 Application.Run,而 WPF 由 Application 对象管理,您可以在 Exit 事件中执行清理。

5. 实践建议

  • 在 Loaded 中执行界面初始化:因为此时窗口已测量完成,设置数据上下文、焦点等是安全的。
  • 在 ContentRendered 中执行依赖渲染完成的操作:例如截图、获取实际渲染尺寸等。
  • 在 Closing 中询问保存:设置 e.Cancel = true 可阻止关闭。
  • 在 Application.Exit 中保存全局状态:例如用户设置、日志等。
  • 注意 Application 的 ShutdownMode:如果您的程序有多个窗口且希望主窗口关闭时退出,记得设置 ShutdownMode="OnMainWindowClose"

6. 扩展:与您最初问题的联系

您之前遇到的单实例 Mutex 问题,实际上影响了 Application 的启动过程。在 OnStartup 中检查 Mutex 并决定是否调用 Shutdown(),这正是在 Startup 事件中干预生命周期——如果检测到已有实例,调用 Shutdown() 会立即终止应用程序,之后的事件(如窗口创建)都不会发生。

理解窗口生命周期后,您可以在适当的事件中处理更多场景,例如:

  • Activated 中刷新数据(当用户切换回程序时)。
  • Deactivated 中暂停动画或降低资源占用。
  • DispatcherUnhandledException 中记录崩溃日志并尝试恢复。

http://www.jsqmd.com/news/495683/

相关文章:

  • 5分钟搞定XTTS语音克隆:从OBS录音到完美WAV格式转换(附Python脚本)
  • 第七章 回溯算法part04
  • VSCode 2026日志插件配置秘钥泄露(内部文档截图+7步零配置接入K8s日志流)
  • haihong Os 鸿蒙开源版开发一个pc版软件应用(1)
  • 北京朗格维修哪里好?六大城高端腕表故障排查+养护实用指南 - 时光修表匠
  • 上海徐汇区老房翻新装修公司哪家专业
  • ChatTTS部署进阶教程:Docker镜像自定义与API封装
  • 柔性振动盘与AI柔性摆盘机:重塑现代制造业的智能上料新范式
  • 服务器网卡设置一个静态IP,ipconfig之后出现两个IP,网络适配器中配置确实设置一个静态IP,现在怎么去掉下面那个,求解?
  • 获取的京东e卡在哪里可以回收兑换? - 抖抖收
  • 通义千问3-Reranker-0.6B效果实测:中英文混合文本排序案例分享
  • 手把手教你用XMind 2025打造高效学习系统:从康奈尔笔记到记忆曲线
  • 华为S5735交换机Telnet/SSH配置全攻略:从VLAN划分到用户认证一步到位
  • 剖析2026年余热锅炉控制系统供应商排名,睿控自动化优势凸显 - 工业设备
  • 欧洲航司二字码
  • 如何通过microG实现Android自由生态:终极解决方案完全指南
  • 说说全国循环流化床锅炉控制个性化定制,哪家品牌靠谱且性价比高 - 工业品牌热点
  • 电池充电放电控制的Matlab/Simulink仿真模型搭建
  • 2026六大城市高端腕表“价格迷局”终极档案:从北京百达翡丽1.5万洗油到南京欧米茄299元陷阱,你的保养费到底花在哪? - 时光修表匠
  • Alpha Shapes算法避坑指南:为什么你的点云轮廓提取总出错?
  • jemter之接口
  • 超表面(Metasurfaces)技术,将热释电探测器,提速到了皮秒级别
  • Fish-Speech-1.5镜像:基于Xinference部署,稳定高效的TTS服务
  • 【H5 前端开发笔记】第 02 期:HTML标签之间的关系、HTML注释、标签属性
  • 小白易懂!ESXi DCUI 登录审计全解(含实操脚本)
  • 手把手教你用Docker Compose离线部署OpenIM(含Nginx配置避坑指南)
  • 清洁度全自动检测设备性能评估:从样品前处理到数据分析 - 西恩士工业 - 工业设备研究社
  • 松材线虫病检测仪 松材线虫快速检测系统
  • 手机膜编码组合版(小红书改微信小店) 2026-3-18
  • 国产CRM系统哪个好?十大高性价比适合大中型企业的CRM排行 - SaaS软件-点评