Události životnosti objektů (WPF .NET)

Během své životnosti procházejí všechny objekty ve spravovaném kódu Microsoft .NET fázemi vytváření, používání a zničení . Windows Presentation Foundation (WPF) poskytuje oznámení o těchto fázích, ke kterým dochází u objektu, vyvoláním událostí životnosti. Pro elementy na úrovni architektury WPF (vizuální objekty) WPF implementuje Initializedudálosti , Loadeda Unloaded životnosti. Vývojáři můžou tyto události životnosti používat jako hooky pro operace za kódem, které zahrnují prvky. Tento článek popisuje události životnosti pro vizuální objekty a pak zavádí další události životnosti, které se konkrétně vztahují na prvky oken, hostitele navigace nebo objekty aplikace.

Důležité

Dokumentace k desktopové příručce pro .NET 7 a .NET 6 se právě připravuje.

Předpoklady

Tento článek předpokládá základní znalosti o tom, jak lze rozložení elementu WPF konceptualizovat jako strom a že jste si přečetli přehled směrovaných událostí. Pokud chcete postupovat podle příkladů v tomto článku, pomůže vám to, pokud znáte jazyk XAML (Extensible Application Markup Language) a víte, jak psát aplikace WPF.

Události životnosti pro objekty vizuálu

Prvky na úrovni architektury WPF jsou odvozeny z FrameworkElement nebo FrameworkContentElement. Události Initialized, Loadeda Unloaded životnosti jsou společné pro všechny prvky architektury WPF. Následující příklad ukazuje strom elementu, který je primárně implementován v XAML. XAML definuje nadřazený Canvas prvek, který obsahuje vnořené elementy, které každý používá syntaxi atributu XAML pro připojení Initialized, Loadeda Unloaded obslužné rutiny událostí životnosti.

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

Jedním z elementů XAML je vlastní ovládací prvek, který je odvozen od základní třídy, která přiřazuje obslužné rutiny události životnosti v kódu za sebou.

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.

Výstup programu zobrazuje pořadí vyvolání Initializedudálostí , Loadeda Unloaded životnosti u každého objektu stromu. Tyto události jsou popsány v následujících částech v pořadí, v jakém jsou vyvolány u každého objektu stromu.

Inicializovaná událost životnosti

Systém událostí WPF vyvolá událost u elementu Initialized :

  • Když jsou nastaveny vlastnosti elementu.
  • Přibližně ve stejnou dobu, kdy je objekt inicializován voláním jeho konstruktoru.

Některé vlastnosti elementu, například Panel.Children, mohou obsahovat podřízené prvky. Nadřazené prvky nemůžou inicializovat sestavy, dokud nebudou inicializovány jejich podřízené prvky. Hodnoty vlastností se tedy nastavují od nejrozsáhlejších vnořených elementů ve stromu elementů a následné nadřazené prvky až do kořenového adresáře aplikace. Vzhledem k tomu, že Initialized událost nastane, když jsou vlastnosti elementu nastaveny, tato událost je nejprve vyvolána na nejmíň vnořené elementy definované v kódu, následované následnými nadřazenými prvky až do kořenového adresáře aplikace. Pokud se objekty dynamicky vytvářejí v kódu za sebou, může být jejich inicializace mimo posloupnost.

Systém událostí WPF nečeká na inicializaci všech prvků ve stromu elementu Initialized před vyvolání události na elementu. Takže když napíšete obslužnou rutinu Initialized události pro libovolný prvek, mějte na paměti, že okolní prvky v logickém nebo vizuálním stromu, zejména nadřazené prvky, nebyly vytvořeny. Nebo mohou být jejich členské proměnné a datové vazby neinicializovány.

Poznámka:

Initialized Když je událost vyvolána u elementu, výrazy elementu, jako jsou dynamické prostředky nebo vazby, budou nehodnocené.

Načtená událost životnosti

Systém událostí WPF vyvolá událost u elementu Loaded :

  • Pokud je logický strom obsahující prvek dokončen a připojen ke zdroji prezentace. Zdroj prezentace poskytuje úchyt okna (HWND) a vykreslovací plochu.
  • Když jsou datové vazby k místním zdrojům, například k jiným vlastnostem nebo přímo definovaným zdrojům dat, dokončeny.
  • Jakmile systém rozložení vypočítá všechny potřebné hodnoty pro vykreslování.
  • Před konečným vykreslením.

Událost Loaded není vyvolána u žádného prvku ve stromu elementu, dokud nebudou načteny všechny prvky v rámci logického stromu . Systém událostí WPF nejprve vyvolá Loaded událost na kořenovém prvku stromu elementů a pak na každém po sobě jdoucím podřízeného elementu až po nejhrozšířenější vnořené elementy. I když tato událost může vypadat podobně jako tunelová událost, Loaded událost nepřenáší data událostí z jednoho prvku do druhého, takže označení události jako zpracovávané nemá žádný vliv.

Poznámka:

Systém událostí WPF nemůže zaručit, že se před Loaded událostí dokončily asynchronní datové vazby. Asynchronní datové vazby se sváže s externími nebo dynamickými zdroji.

Událost unloaded lifetime

Systém událostí WPF vyvolá událost u elementu Unloaded :

  • Při odstranění jejího zdroje prezentace nebo
  • Při odebrání nadřazeného vizuálu

Systém událostí WPF nejprve vyvolá Unloaded událost na kořenovém prvku stromu elementů a pak na každém po sobě jdoucím podřízeného elementu až po nejhrozšířenější vnořené elementy. I když se tato událost může podobat trasované události tunelu , Unloaded událost nerozšířuje data událostí z elementu do elementu, takže označení události jako zpracovávané nemá žádný vliv.

Unloaded Když je událost vyvolána u elementu, je to nadřazený prvek nebo jakýkoli prvek vyšší v logickém nebo vizuálním stromu již pravděpodobně nebyl nastaven. Zrušením nastavení znamená, že datové vazby elementu, odkazy na prostředky a styly už nejsou nastavené na jejich normální nebo poslední známou hodnotu za běhu.

Jiné události životnosti

Z hlediska událostí životnosti existují čtyři hlavní typy objektů WPF: prvky obecně, prvky okna, hostitele navigace a objekty aplikace. Události Initialized, Loadeda Unloaded životnosti se vztahují na všechny prvky na úrovni architektury. Jiné události životnosti se konkrétně vztahují na prvky okna, hostitele navigace nebo objekty aplikace. Informace o těchto dalších událostech životnosti najdete tady:

Viz také