控件的生命周期

UserControl 的生命周期

UserControl 继承自 Control,因此它的生命周期与所有 Control 类型相同。主要的生命周期事件包括:

1. Loaded 事件

Loaded 事件在控件完全构建在可视树中,并且布局和渲染都完成后触发。 Control.cs:174-183

触发时机:

  • 控件附加到可视树后(OnAttachedToVisualTreeCore) Control.cs:382-389
  • 控件模板已应用,模板中创建的对象引用可用
  • 这是控件创建生命周期中最晚的时机

实现机制:

控件附加到可视树时会调用 ScheduleOnLoadedCore(),将控件添加到加载队列中: Control.cs:294-308

加载队列会在 Dispatcher 的 Loaded 优先级上批量处理,以提高性能: Control.cs:260-288

最终调用 OnLoadedCore() 触发 Loaded 事件: Control.cs:314-328

2. Unloaded 事件

Unloaded 事件在控件从可视树中移除时触发。 Control.cs:190-201

触发时机:

  • 控件从可视树分离时
  • 与 Loaded 对称,用于清理资源

实现机制: Control.cs:334-352

3. Window 的特殊处理

Window 和 WindowBase 作为可视树根节点,不会触发 OnAttachedToVisualTreeCore,因此需要手动调度 Loaded/Unloaded 事件: WindowBase.cs:208-227

在Control被挂载到可视树之前,会有以下几个关键的生命周期阶段:

1. 构造函数 (Constructor)

控件实例化时调用,这是生命周期的起点。

2. BeginInit() / EndInit()

Control 继承自 StyledElement,实现了 ISupportInitialize 接口。link to Repo AvaloniaUI/Avalonia: src/Avalonia.Base/StyledElement.cs:350-368

BeginInit():

  • 在 XAML 解析开始时调用
  • 增加 _initCount 计数器,表示初始化开始

EndInit():

  • 在 XAML 解析完成、所有属性设置后调用
  • 减少 _initCount 计数器
  • 当 _initCount 为 0 且控件已附加到逻辑树时,会触发样式应用和初始化

测试代码验证了初始化顺序:link to Repo AvaloniaUI/Avalonia: tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs:686-708

控件会在附加到父控件之后、最终 EndInit 之前被添加到逻辑树。

3. AttachedToLogicalTree

控件附加到逻辑树时触发,发生在附加到可视树之前。

测试验证了顺序:link to Repo AvaloniaUI/Avalonia: tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs:663-684

控件会在属性设置之前被添加到父控件。

4. ApplyStyling()

在 EndInit() 中,如果控件已附加到逻辑树,会调用 ApplyStyling()。link to Repo AvaloniaUI/Avalonia: src/Avalonia.Base/StyledElement.cs:381-414

这个方法会:

  • 应用控件主题 (ApplyControlTheme)
  • 应用模板化父控件主题 (ApplyTemplatedParentControlTheme)
  • 应用样式 (ApplyStyles)

5. InitializeIfNeeded()

在样式应用后调用,设置 IsInitialized 为 true。link to Repo AvaloniaUI/Avalonia: src/Avalonia.Base/StyledElement.cs:416-420

6. OnInitialized()

当 IsInitialized 设置为 true 后触发的虚方法,子类可以重写。link to Repo AvaloniaUI/Avalonia: src/Avalonia.Base/StyledElement.cs:614-616

7. OnAttachedToVisualTreeCore()

控件附加到可视树时调用。link to Repo AvaloniaUI/Avalonia: src/Avalonia.Controls/Control.cs:382-389 这个方法会:

  • 调用 InitializeIfNeeded() 确保控件已初始化
  • 调用 ScheduleOnLoadedCore() 安排 Loaded 事件

完整的挂载前生命周期顺序

![[Pasted image 20251108222519.png]]