【WPF.NET开发】对象生存期事件

本文内容

  1. 先决条件
  2. 视觉对象的生存期事件
  3. 其他生存期事件

在所有对象的生存期内,Microsoft .NET 托管代码中的所有对象都会经历"创建"、"使用"和"销毁"的阶段。 当关于这些阶段的通知出现在对象上时,Windows Presentation Foundation (WPF) 会通过引发生存期事件来进行提供。 对于 WPF 框架级元素(视觉对象),WPF 会实现 InitializedLoadedUnloaded 生存期事件。 开发人员可以将这些生存期事件用作涉及元素的代码隐藏操作的挂钩。 本文先介绍视觉对象的生存期事件,然后介绍专门应用于窗口元素、导航宿主或应用程序对象的其他生存期事件。

1、先决条件

本文假定你已基本了解如何将 WPF 元素布局概念化为树,并且你已经阅读过路由事件概述

。 若要理解本文中的示例,还应当熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 WPF 应用程序。

2、视觉对象的生存期事件

WPF 框架级元素派生自 FrameworkElementFrameworkContentElementInitializedLoadedUnloaded 生存期事件是所有 WPF 框架级别元素所通用的。 以下示例演示主要在 XAML 中实现的元素树。 XAML 定义一个父 Canvas 元素,其中包含嵌套元素,每个元素都使用 XAML 属性语法附加 InitializedLoadedUnloaded 生存期事件处理程序。

复制代码
<Canvas x:Name="canvas">
    <StackPanel x:Name="outerStackPanel" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
        <custom:ComponentWrapper x:Name="componentWrapper" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
            <TextBox Name="textBox1" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
            <TextBox Name="textBox2" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
        </custom:ComponentWrapper>
    </StackPanel>
    <Button Content="Remove canvas child elements" Click="Button_Click"/>
</Canvas>

其中一个 XAML 元素是自定义控件,它派生自在代码隐藏中分配生存期事件处理程序的基类。

复制代码
public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    // Handler for the Initialized lifetime event (attached in XAML).
    private void InitHandler(object sender, System.EventArgs e) => 
        Debug.WriteLine($"Initialized event on {((FrameworkElement)sender).Name}.");

    // Handler for the Loaded lifetime event (attached in XAML).
    private void LoadHandler(object sender, RoutedEventArgs e) => 
        Debug.WriteLine($"Loaded event on {((FrameworkElement)sender).Name}.");

    // Handler for the Unloaded lifetime event (attached in XAML).
    private void UnloadHandler(object sender, RoutedEventArgs e) =>
        Debug.WriteLine($"Unloaded event on {((FrameworkElement)sender).Name}.");

    // Remove nested controls.
    private void Button_Click(object sender, RoutedEventArgs e) => 
        canvas.Children.Clear();
}

// Custom control.
public class ComponentWrapper : ComponentWrapperBase { }

// Custom base control.
public class ComponentWrapperBase : StackPanel
{
    public ComponentWrapperBase()
    {
        // Assign handler for the Initialized lifetime event (attached in code-behind).
        Initialized += (object sender, System.EventArgs e) => 
            Debug.WriteLine($"Initialized event on componentWrapperBase.");

        // Assign handler for the Loaded lifetime event (attached in code-behind).
        Loaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Loaded event on componentWrapperBase.");

        // Assign handler for the Unloaded lifetime event (attached in code-behind).
        Unloaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Unloaded event on componentWrapperBase.");
    }
}

/* Output:
Initialized event on textBox1.
Initialized event on textBox2.
Initialized event on componentWrapperBase.
Initialized event on componentWrapper.
Initialized event on outerStackPanel.

Loaded event on outerStackPanel.
Loaded event on componentWrapperBase.
Loaded event on componentWrapper.
Loaded event on textBox1.
Loaded event on textBox2.

Unloaded event on outerStackPanel.
Unloaded event on componentWrapperBase.
Unloaded event on componentWrapper.
Unloaded event on textBox1.
Unloaded event on textBox2.
*/

程序输出显示在每个树对象上调用 InitializedLoadedUnloaded 生存期事件的顺序。 以下各节按在每个树对象上引发这些事件的顺序对其进行介绍。

2.1 初始化的生存期事件

在以下情况下,WPF 事件系统会在元素上引发 Initialized 事件:

  • 设置元素的属性时。
  • 大约在同一时间通过调用对象构造函数对其进行初始化。

某些元素属性(如 Panel.Children)可以包含子元素。 父元素在初始化其子元素之前无法报告初始化。 因此,从元素树中嵌套最深的元素开始设置属性值,后跟连续父元素,一直到应用程序根。 由于在设置元素的属性时发生 Initialized 事件,因此首先在标记中定义的嵌套最深的元素上调用该事件,后跟连续父元素,一直到应用程序根。 在代码隐藏中动态创建对象时,其初始化可能不按顺序进行。

WPF 事件系统不会等待元素树中的所有元素都完成初始化,然后再对元素引发 Initialized 事件。 因此,在为任何元素编写 Initialized 事件处理程序时,请记住,逻辑树或可视化树中的周围元素(尤其是父元素)可能尚未创建。 或者,其成员变量和数据绑定可能未初始化。

备注

在元素上引发 Initialized 事件时,将取消计算元素的表达式用法,例如动态资源或绑定。

2.2 加载的生存期事件

在以下情况下,WPF 事件系统会在元素上引发 Loaded 事件:

  • 当包含该元素的逻辑树完成并连接到演示文稿源时。 演示源提供窗口句柄 (HWND) 和呈现图面。
  • 当数据绑定到本地源(例如其他属性或直接定义的数据源)完成时。
  • 在布局系统已计算呈现所需的所有值后。
  • 在最终呈现之前。

在加载

逻辑树中的所有元素之前,不会在元素树中的任何元素上引发 Loaded 事件。 WPF 事件系统首先在元素树的根元素上引发 Loaded 事件,然后在每个连续的子元素上向下引发嵌套最深的元素。 尽管此事件可能类似于

隧道路由事件,但 Loaded 事件不会将事件数据从一个元素传输到另一个元素,因此将事件标记为已处理没有效果。

备注

WPF 事件系统无法保证异步数据绑定在 Loaded 事件之前已经完成。 异步数据绑定会绑定到外部或动态源。

2.3 卸载的生存期事件

在以下情况下,WPF 事件系统会在元素上引发 Unloaded 事件:

  • 删除其演示文稿源时,或
  • 删除其视觉对象父级时。

WPF 事件系统首先在元素树的根元素上引发 Unloaded 事件,然后在每个连续的子元素上向下引发嵌套最深的元素。 尽管此事件可能类似于

隧道路由事件,但 Unloaded 事件不会将事件数据在元素间传播,因此将事件标记为已处理没有效果。

Unloaded 元素上引发事件时,它的元素或逻辑树或可视化树中更高级的元素可能已取消设置。 取消设置意味着元素的数据绑定、资源引用和样式不再设置为其正常或上次已知运行时值。

3、其他生存期事件

从生存期事件角度来看,主要有四种 WPF 对象类型:常规元素、窗口元素、导航宿主和应用程序对象。 InitializedLoadedUnloaded 生存期事件适用于所有框架级元素。 其他生存期事件专门应用于窗口元素、导航宿主或应用程序对象。

相关推荐
凯子坚持 c21 分钟前
CANN 性能剖析实战:从原始事件到交互式火焰图
windows·microsoft
JQLvopkk22 分钟前
C# 轻量级工业温湿度监控系统(含数据库与源码)
开发语言·数据库·c#
开开心心就好1 小时前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
獨枭1 小时前
PyCharm 跑通 SAM 全流程实战
windows
仙剑魔尊重楼2 小时前
音乐制作电子软件FL Studio2025.2.4.5242中文版新功能介绍
windows·音频·录屏·音乐·fl studio
PHP小志2 小时前
Windows 服务器怎么修改密码和用户名?账户被系统锁定如何解锁
windows
wxin_VXbishe3 小时前
C#(asp.net)学员竞赛信息管理系统-计算机毕业设计源码28790
java·vue.js·spring boot·spring·django·c#·php
无心水3 小时前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf
专注VB编程开发20年4 小时前
vb.net datatable新增数据时改用数组缓存
java·linux·windows
仙剑魔尊重楼4 小时前
专业音乐制作软件fl Studio 2025.2.4.5242中文版新功能
windows·音乐·fl studio