Zdarzenia okresu istnienia obiektu (WPF .NET)

W okresie ich istnienia wszystkie obiekty w kodzie zarządzanym platformy Microsoft .NET przechodzą przez etapy tworzenia, używania i niszczenia . Program Windows Presentation Foundation (WPF) udostępnia powiadomienie o tych etapach, ponieważ występują one w obiekcie, przez podniesienie zdarzeń okresu istnienia. W przypadku elementów na poziomie struktury WPF (obiektów wizualnych) WPF implementuje Initializedzdarzenia , Loadedi Unloaded okresu istnienia. Deweloperzy mogą używać tych zdarzeń okresu istnienia jako punktów zaczepienia do operacji związanych z kodem, które obejmują elementy. W tym artykule opisano zdarzenia okresu istnienia obiektów wizualizacji, a następnie wprowadzono inne zdarzenia okresu istnienia, które mają zastosowanie do elementów okna, hostów nawigacji lub obiektów aplikacji.

Ważne

Dokumentacja przewodnika dla komputerów dla platform .NET 7 i .NET 6 jest w budowie.

Wymagania wstępne

W tym artykule przyjęto założenie, że podstawowa wiedza na temat sposobu, w jaki układ elementów WPF może być koncepcyjny jako drzewo, oraz że przeczytano omówienie zdarzeń trasowanych. Aby postępować zgodnie z przykładami w tym artykule, warto zapoznać się z językiem Extensible Application Markup Language (XAML) i wiedzieć, jak pisać aplikacje WPF.

Zdarzenia okresu istnienia dla obiektów wizualizacji

Elementy na poziomie struktury WPF pochodzą z FrameworkElement elementu lub FrameworkContentElement. Zdarzenia Initialized, Loadedi Unloaded okresu istnienia są wspólne dla wszystkich elementów na poziomie platformy WPF. W poniższym przykładzie przedstawiono drzewo elementów, które jest implementowane głównie w języku XAML. Język XAML definiuje element nadrzędny Canvas zawierający zagnieżdżone elementy, które używają składni atrybutów XAML do dołączania InitializedLoadedprogramów obsługi zdarzeń , i Unloaded okresu istnienia.

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

Jednym z elementów XAML jest kontrolka niestandardowa, która pochodzi z klasy bazowej, która przypisuje programy obsługi zdarzeń okresu istnienia w kodzie.

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.

Dane wyjściowe programu pokazują kolejność wywołań Initializedzdarzeń , Loadedi Unloaded okresu istnienia dla każdego obiektu drzewa. Te zdarzenia są opisane w poniższych sekcjach w kolejności, w której są one wywoływane na każdym obiekcie drzewa.

Zdarzenie początkowego okresu istnienia

System zdarzeń WPF zgłasza Initialized zdarzenie elementu:

  • Po ustawieniu właściwości elementu.
  • Około tego samego czasu obiekt jest inicjowany przez wywołanie jego konstruktora.

Niektóre właściwości elementów, takie jak Panel.Children, mogą zawierać elementy podrzędne. Elementy nadrzędne nie mogą zgłaszać inicjowania, dopóki ich elementy podrzędne nie zostaną zainicjowane. Dlatego wartości właściwości są ustawiane począwszy od najbardziej zagnieżdżonych elementów w drzewie elementów, a następnie kolejnych elementów nadrzędnych do katalogu głównego aplikacji. Initialized Ponieważ zdarzenie występuje, gdy właściwości elementu są ustawione, to zdarzenie jest najpierw wywoływane na najbardziej głęboko zagnieżdżonych elementach zgodnie z definicją w adiustacji, a następnie kolejne elementy nadrzędne do katalogu głównego aplikacji. Gdy obiekty są tworzone dynamicznie w kodzie, ich inicjowanie może nie być sekwencyjne.

System zdarzeń WPF nie czeka, aż wszystkie elementy w drzewie elementów zostaną zainicjowane przed podniesieniem Initialized zdarzenia na elemekcie. Dlatego podczas pisania procedury obsługi zdarzeń Initialized dla dowolnego elementu należy pamiętać, że otaczające elementy w drzewie logicznym lub wizualnym, szczególnie elementy nadrzędne, mogły nie zostać utworzone. Lub ich zmienne składowe i powiązania danych mogą być niezainicjowane.

Uwaga

Initialized Gdy zdarzenie jest wywoływane w elememencie, użycie wyrażeń elementu, takie jak zasoby dynamiczne lub powiązanie, będzie nieowarte.

Załadowane zdarzenie okresu istnienia

System zdarzeń WPF zgłasza Loaded zdarzenie elementu:

  • Gdy drzewo logiczne zawierające element zostanie ukończone i połączone ze źródłem prezentacji. Źródło prezentacji udostępnia uchwyt okna (HWND) i powierzchnię renderowania.
  • Gdy powiązanie danych ze źródłami lokalnymi, takie jak inne właściwości lub bezpośrednio zdefiniowane źródła danych, zostanie ukończone.
  • Po obliczeniu wszystkich niezbędnych wartości do renderowania przez system układu.
  • Przed ostatecznym renderowaniem.

Zdarzenie Loaded nie jest wywoływane dla żadnego elementu w drzewie elementów, dopóki wszystkie elementy w drzewie logicznym nie zostaną załadowane. System zdarzeń WPF najpierw zgłasza Loaded zdarzenie w elemecie głównym drzewa elementów, a następnie na każdym kolejnym elemedycie podrzędnym w dół do najbardziej głęboko zagnieżdżonych elementów. Mimo że to zdarzenie może przypominać zdarzenie kierowane przez tunelowanie , Loaded zdarzenie nie przenosi danych zdarzeń z jednego elementu do drugiego, dlatego oznaczanie zdarzenia jako obsłużonego nie ma wpływu.

Uwaga

System zdarzeń WPF nie może zagwarantować, że powiązania danych asynchronicznych zostały ukończone przed zdarzeniem Loaded . Powiązania danych asynchronicznych wiążą się ze źródłami zewnętrznymi lub dynamicznymi.

Zdarzenie okresu istnienia rozładowanego

System zdarzeń WPF zgłasza Unloaded zdarzenie elementu:

  • Usunięcie źródła prezentacji lub
  • Po usunięciu jej elementu nadrzędnego wizualizacji.

System zdarzeń WPF najpierw zgłasza Unloaded zdarzenie w elemecie głównym drzewa elementów, a następnie na każdym kolejnym elemedycie podrzędnym w dół do najbardziej głęboko zagnieżdżonych elementów. Mimo że to zdarzenie może przypominać zdarzenie kierowane przez tunelowanie , Unloaded zdarzenie nie propaguje danych zdarzeń z elementu do elementu, dlatego oznaczanie zdarzenia jako obsłużonego nie ma wpływu.

Unloaded Gdy zdarzenie jest wywoływane na elemecie, element nadrzędny lub dowolny element wyższy w drzewie logicznym lub wizualnym mógł już nie zostać zdenerwowany. Nieustawiono oznacza, że powiązania danych, odwołania do zasobów i style elementu nie są już ustawione na normalną lub ostatnią znaną wartość czasu wykonywania.

Inne zdarzenia okresu istnienia

Z perspektywy zdarzeń okresu istnienia istnieją cztery główne typy obiektów WPF: elementy ogólne, elementy okna, hosty nawigacji i obiekty aplikacji. Zdarzenia Initialized, Loadedi Unloaded okresu istnienia mają zastosowanie do wszystkich elementów na poziomie platformy. Inne zdarzenia okresu istnienia dotyczą konkretnie elementów okna, hostów nawigacji lub obiektów aplikacji. Aby uzyskać informacje o tych innych zdarzeniach okresu istnienia, zobacz:

Zobacz też