WPF 应用程序的生命周期事件






4.19/5 (17投票s)
WPF 应用程序的生命周期事件。
介绍
本文档是为初学者准备的教程。它将介绍 WPF 应用程序的生命周期事件。
WPF 新手常常遇到的一个常见问题是,他们不理解事件的顺序,这会在他们尝试添加初始化、清理或安全关闭代码时造成困惑。在本文中,我将重点介绍相关的基本概念。
WPF 中的事件
我们可以将 WPF 中的事件分为生命周期事件、输入事件和自定义事件。
输入事件是指与鼠标、键盘、触笔和手势相关的事件。
自定义事件是指开发者通过声明自己的委托和围绕它的事件包装器来实现的事件。
我们将只关注生命周期事件。
生命周期事件
任何对象在其生命周期中都会经历创建、使用和销毁。在这里,我将具体描述 WPF 对象 Window 和 Application 的生命周期事件。这些对象都派生自 Framework element。
我将按照它们发生的顺序描述下面的生命周期事件。
先是初始化顺序,然后是关闭顺序。
事件初始化顺序:
任何派生自 Framework 类的 WPF 对象都将经历 initialized(初始化)、loaded(加载)和 unloaded(卸载)。 虽然示例程序显示了 Application、Window 和子对象(简单的按钮)重写并处理生命周期事件。
Startup: (Application)
这是 Application 的第一个被触发的生命周期事件。当在主窗口上调用 Application.Run()
时,它会被触发。但在主窗口显示之前。请注意,Application.Run()
是对用户隐藏的。如果你想查看编译器生成的代码,请在你的 projec\obj 文件夹中搜索名为 App.g.i.cs 的文件(g 代表 generated,即生成的)。
这是你可以处理应用程序收到的任何命令行参数的事件。
Initialized: (Window)
这是 Window 的第一个被触发的生命周期事件。这是一个普通的 .Net 事件,而不是路由事件。当此事件在窗口级别被触发时,意味着其所有嵌套的子控件也已经初始化。因此,子控件将触发它们的 Initialized 事件,然后是父控件,最后是 Window。 (查看示例程序,你会发现“Button_Initialized”事件在“Window_Initialized”之前被触发)
当窗口被实例化时,会发生此事件。此事件在基类 FrameworkElement
级别。请注意,样式和数据绑定在此级别将不适用。有趣的是,FrameworkElement
定义了动画、样式和 DataBinding
的服务。
SourceInitialized : (Window)
为你的窗口获取一个合适的传统句柄。 但此时你的窗口仍然不可见。
值得注意的是,这个顶层窗口事件没有对应的子控件事件。因为 WPF 的子控件没有与之关联的 HWND,这与 Winforms 模型截然不同。请查看此链接以获得更深入的理解 https://codeproject.org.cn/Articles/133632/Win32-Handle-HWND-WPF-Objects-A-Note
Activated: (Application)
每次当应用程序的窗口获得焦点时,以及第一次渲染应用程序窗口时都会被调用。请注意,只有在此事件之后,窗口的 Activated
事件才会被触发,这才是真正有意义的。
Activated: (Window)
等同于控件的 GotFocus
。每次当窗口获得焦点时,以及第一次渲染窗口时都会被调用。只有在此事件之后,窗口的 loaded 事件 isfired
。
Loaded: (Window)
你的整个窗口都已准备就绪。渲染前的最后一个阶段。所有动画、样式和数据绑定都将在此准备好。 任何视觉调整都应该在此完成。
与 Initialized 事件相比,这里的顺序是相反的。它从完全构造的逻辑元素树的根到子元素引发。所以窗口的 Load 事件会先被引发,然后是任何子元素的事件。
(查看示例程序,你会发现“Button_Loaded”事件在“Window_Loaded”之后被触发)
ContentRendered: (Window)
顾名思义,它在内容渲染后发生。如果没有内容,此事件根本不会被触发。 不要在此执行任何视觉调整。从这里开始,你可以为你的业务逻辑设置一个标志,表示窗口已启动、正在运行并首次显示给用户。
事件关闭顺序:
Closing: (Window)
触发可以是用户操作或程序化操作。用户操作可以是直接的,例如点击关闭按钮。 从 Windows 注销不会引发此事件。(示例中处理了 SessionEnding
事件,但此处不讨论)对于你的程序,它可以是调用 Window.Close()
或 Application.ShutDown()
。在任何情况下,都可以通过重写 OnClosing()
并将 CancelEventArgs.Cancel
设置为 true 来取消事件。
Deactivated: (Window)
当窗口失去焦点时(这是窗口等同于 control.GotFocus()
)或关闭时发生。
Deactivated: (Application)
当用户切换到另一个应用程序时(通过 Alt-Tab、任务栏或任务管理器等)或作为应用程序关闭的结果时发生。
Closed: (Window)
窗口已关闭,但窗口元素仍然可以访问。如果出于某种原因需要访问它们,这是最后一个机会。请注意,在此之后将触发 window unloaded。
Exit: (Application)
最后但并非最不重要的。只有 Run()
方法返回。(请参阅上面的 startup 事件,了解关于 Run()
方法的说明)。但是,如果你编写了自己的自定义 main()
方法而不是生成的,你仍然可以在此处添加一些业务逻辑代码。任何快速资源释放都可以在这里完成。
其他生命周期事件
Unloaded
在 WPF Web 应用程序中,页面导航时会发生。当窗口主题更改时也会触发。(当示例程序运行时,尝试更改你的 Windows 主题来验证这一点。)
SessionEnding
当用户注销系统时会触发此事件。可以通过将 SessionEndingCancelEventArgs e.cancel
设置为 true 来取消。
关于示例代码
请找到一个 WPF 应用程序,它可以单独和组合地列出窗口和应用程序的生命周期事件。因为当某些应用程序事件被引发时,窗口尚未创建,所以记录事件数据变得很重要。虽然简单的日志记录就足够了,但我使用了一个 WPF 托管的 WCF 客户端来模拟。请在运行“OrderOfEvents”项目之前运行“DataLogHostSvc”日志记录窗口。除此之外,附件示例本身就具有说明性。
注意:由于此示例使用 net.tcp 绑定,你的 Windows 防火墙可能会阻止它,你需要添加例外。
参考文献
http://msdn.microsoft.com/en-us/library/ms754221.aspx
书籍:《Pro WPF in C# 2010》- Matthew MacDonald