События времени существования объекта (WPF .NET)

Во время их существования все объекты в управляемом коде Microsoft .NET проходят этапы создания, использования и уничтожения . Windows Presentation Foundation (WPF) предоставляет уведомление об этих этапах, так как они происходят в объекте, вызывая события времени существования. Для элементов на уровне платформы WPF (визуальные объекты), WPF реализует InitializedLoadedсобытия времени существования и Unloaded события времени существования. Разработчики могут использовать эти события времени существования в качестве перехватчиков для операций программной части, которые включают элементы. В этой статье описываются события времени существования визуальных объектов, а затем представлены другие события времени существования, которые специально применяются к элементам окна, узлам навигации или объектам приложений.

Важно!

Документация по рабочему столу для .NET 7 и .NET 6 находится в стадии разработки.

Необходимые компоненты

В этой статье предполагается, что базовые знания о том, как макет элемента WPF можно концептуально рассматривать как дерево, и что вы прочитали обзор событий Routed. Чтобы понимать примеры в этой статье полезно познакомиться с языком XAML и узнать, как создавать приложения WPF.

События времени существования для визуальных объектов

Элементы уровня платформы WPF являются производными от FrameworkElement или FrameworkContentElement. LoadedСобытия Initialized, и Unloaded время существования являются общими для всех элементов уровня платформы WPF. В следующем примере показано дерево элементов, которое в основном реализовано в XAML. XAML определяет родительский Canvas элемент, содержащий вложенные элементы, которые используют синтаксис атрибута XAML для присоединения Initializedи LoadedUnloaded обработчиков событий времени существования.

<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.
*/
Partial Public Class MainWindow
    Inherits Window

    Public Sub New()
        InitializeComponent()
    End Sub

    ' Handler for the Initialized lifetime event (attached in XAML).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine($"Initialized event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in XAML).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Loaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in XAML).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Unloaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        ' Remove nested controls.
        canvas.Children.Clear()
    End Sub
End Class

' Custom control.
Public Class ComponentWrapper
    Inherits ComponentWrapperBase
End Class

' Custom base control.
Public Class ComponentWrapperBase
    Inherits StackPanel

    Public Sub New()
        ' Attach handlers for the lifetime events.
        AddHandler Initialized, AddressOf InitHandler
        AddHandler Loaded, AddressOf LoadHandler
        AddHandler Unloaded, AddressOf UnloadHandler
    End Sub

    ' Handler for the Initialized lifetime event (attached in code-behind).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine("Initialized event on componentWrapperBase.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in code-behind).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Loaded event on componentWrapperBase.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in code-behind).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Unloaded event on componentWrapperBase.")
    End Sub
End Class

'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.

Выходные данные программы показывают порядок вызова Initializedсобытий Loadedи Unloaded времени существования для каждого объекта дерева. Эти события описаны в следующих разделах в том порядке, в котором они создаются для каждого объекта дерева.

Инициализированное событие времени существования

Система событий WPF вызывает Initialized событие в элементе:

  • Если заданы свойства элемента.
  • Примерно в то же время, когда объект инициализирован с помощью вызова конструктора.

Некоторые свойства элементов, например Panel.Children, могут содержать дочерние элементы. Родительские элементы не могут сообщать об инициализации, пока их дочерние элементы не инициализированы. Таким образом, значения свойств задаются начиная с наиболее глубоко вложенных элементов в дереве элементов, за которым следует последовательные родительские элементы вплоть до корневого каталога приложения. Initialized Так как событие возникает при установке свойств элемента, это событие сначала вызывается в наиболее глубоко вложенных элементах, как определено в разметке, а затем последовательные родительские элементы вплоть до корневого каталога приложения. Если объекты динамически создаются в коде, их инициализация может быть не последовательной.

Система событий WPF не ожидает инициализации всех элементов в дереве элементов, прежде чем вызывать Initialized событие в элементе. Поэтому при написании обработчика Initialized событий для любого элемента следует помнить, что окружающие элементы в логическом или визуальном дереве, особенно родительские элементы, могут не быть созданы. Кроме того, их переменные-члены и привязки данных могут быть неинициализированы.

Примечание.

Initialized При возникновении события в элементе использование выражений элемента, например динамических ресурсов или привязки, будет неоценимо.

Загруженное событие времени существования

Система событий WPF вызывает Loaded событие в элементе:

  • Когда логическое дерево, содержащее элемент, будет завершено и подключено к источнику презентации. Источник презентации предоставляет дескриптор окна (HWND) и область отрисовки.
  • Когда привязка данных к локальным источникам, например другим свойствам или непосредственно определенным источникам данных, завершается.
  • После того как система макета вычислила все необходимые значения для отрисовки.
  • Перед окончательной отрисовкой.

Событие Loaded не вызывается для любого элемента в дереве элементов, пока все элементы в логическом дереве не загружаются. Система событий WPF сначала вызывает Loaded событие в корневом элементе дерева элементов, а затем на каждом последующем дочернем элементе вплоть до наиболее глубоко вложенных элементов. Хотя это событие может напоминать перенаправленное событие туннелирования , Loaded событие не несет данные о событиях из одного элемента в другой, поэтому маркировка события как обработанная не влияет.

Примечание.

Система событий WPF не может гарантировать, что асинхронные привязки данных завершены до Loaded события. Асинхронные привязки данных привязываются к внешним или динамическим источникам.

Выгрузленное событие времени существования

Система событий WPF вызывает Unloaded событие в элементе:

  • Удаление источника презентации или
  • При удалении визуального родительского элемента.

Система событий WPF сначала вызывает Unloaded событие в корневом элементе дерева элементов, а затем на каждом последующем дочернем элементе вплоть до наиболее глубоко вложенных элементов. Хотя это событие может напоминать перенаправленное событие туннелирования , Unloaded событие не распространяет данные о событиях из элемента в элемент, поэтому маркировка события как обработанного не влияет.

Unloaded При возникновении события в элементе родительскийэлемент или любой элемент выше в логическом или визуальном дереве, возможно, уже не настроен. Unset означает, что привязки данных элемента, ссылки на ресурсы и стили больше не задаются в их обычном или последнем известном значении времени выполнения.

Другие события времени существования

С точки зрения событий времени существования существует четыре основных типа объектов WPF: элементы в целом, элементы окна, узлы навигации и объекты приложения. LoadedСобытия Initializedвремени существования применяются Unloaded ко всем элементам уровня платформы. Другие события времени существования специально применяются к элементам окна, узлам навигации или объектам приложений. Дополнительные сведения об этих других событиях жизни см. в следующем разделе:

См. также