Udostępnij za pośrednictwem


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, gdy występują one w obiekcie, poprzez wywoływanie zdarzeń dotyczących cyklu życia. Dla elementów na poziomie frameworku WPF (obiektów wizualnych) WPF implementuje zdarzenia cyklu życia Initialized, Loadedi Unloaded. 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.

Warunki wstępne

W tym artykule przyjęto założenie, że posiadasz podstawową wiedzę na temat tego, jak układ elementów WPF może być postrzegany jako drzewo, oraz że przeczytano Przegląd 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.

Wydarzenia cyklu życia dla obiektów wizualnych

Elementy na poziomie struktury WPF pochodzą z FrameworkElement lub FrameworkContentElement. Zdarzenia cyklu życia Initialized, Loadedi Unloaded są wspólne dla wszystkich elementów na poziomie frameworka 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 Canvas nadrzędny zawierający zagnieżdżone elementy, które używają składni atrybutów XAML do dołączania programów obsługi zdarzeń Initialized, Loadedi 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 procedury obsługi zdarzeń cyklu życia 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łania zdarzeń Initialized, Loadedi Unloaded związanych z cyklem życia dla każdego obiektu drzewa. Zdarzenia te są opisane w poniższych sekcjach w kolejności, w której są wywoływane na każdym obiekcie drzewa.

Zdarzenie początkowego okresu istnienia

System zdarzeń WPF wywołuje zdarzenie Initialized na elemencie:

  • Po ustawieniu właściwości elementu.
  • W tym samym czasie 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 od najbardziej zagnieżdżonych elementów w drzewie elementów, a następnie w kolejnych elementach nadrzędnych aż do korzenia aplikacji. Jako że zdarzenie Initialized 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 znacznikach, a następnie na kolejne elementy nadrzędne aż do korzenia aplikacji. Gdy obiekty są tworzone dynamicznie w kodzie, ich inicjowanie może nie być sekwencyjne.

System zdarzeń w WPF nie czeka na zainicjowanie wszystkich elementów w drzewie elementów, zanim zostanie wywołane zdarzenie Initialized na elemencie. Dlatego podczas pisania programu 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. Albo ich zmienne składowe oraz powiązania danych mogą być niezainicjowane.

Notatka

Gdy zdarzenie Initialized zostanie zgłoszone w elemencie, wyrażenia używane przez element, takie jak zasoby dynamiczne lub powiązania, będą niewywołane.

Załadowane zdarzenie cyklu życia

System zdarzeń WPF zgłasza zdarzenie Loaded na elemencie:

  • 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 tym, jak system układu obliczy wszystkie niezbędne wartości do renderowania.
  • Przed ostatecznym renderowaniem.

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

Notatka

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 rozładowanego stanu życia

System zdarzeń WPF zgłasza zdarzenie Unloaded na elemencie:

  • Po usunięciu źródła prezentacji albo
  • Po usunięciu jej wizualnego elementu nadrzędnego.

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

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

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 cyklu życia Initialized, Loadedi Unloaded mają zastosowanie do wszystkich elementów na poziomie struktury. 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ż