Événements de durée de vie des objets (WPF .NET)

Pendant leur durée de vie, tous les objets du code managé Microsoft .NET passent par des phases de création, d’utilisation et de destruction . Windows Presentation Foundation (WPF) fournit une notification de ces étapes, car elles se produisent sur un objet, en générant des événements de durée de vie. Pour les éléments au niveau du framework WPF (objets visuels), WPF implémente les événements de durée de vie, Loadedet Unloaded les Initializedévénements de durée de vie. Les développeurs peuvent utiliser ces événements de durée de vie comme hooks pour les opérations code-behind qui impliquent des éléments. Cet article décrit les événements de durée de vie des objets visuels, puis présente d’autres événements de durée de vie qui s’appliquent spécifiquement aux éléments de fenêtre, aux hôtes de navigation ou aux objets d’application.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Prérequis

Cet article suppose une connaissance de base de la façon dont la disposition des éléments WPF peut être conceptualisée en tant qu’arborescence et que vous avez lu la vue d’ensemble des événements routés. Pour suivre les exemples de cet article, il vous aide à connaître le langage XAML (Extensible Application Markup Language) et à savoir comment écrire des applications WPF.

Événements de durée de vie pour les objets visuels

Les éléments au niveau du framework WPF dérivent ou FrameworkElementFrameworkContentElement. Les événements , Loadedet Unloaded la Initializeddurée de vie sont communs à tous les éléments au niveau du framework WPF. L’exemple suivant montre une arborescence d’éléments qui est principalement implémentée en XAML. Le code XAML définit un élément parent Canvas qui contient des éléments imbriqués, qui utilisent chacune une syntaxe d’attribut XAML pour attacher Initialized, Loadedet Unloaded des gestionnaires d’événements de durée de vie.

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

L’un des éléments XAML est un contrôle personnalisé, qui dérive d’une classe de base qui affecte des gestionnaires d’événements de durée de vie dans code-behind.

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.

La sortie du programme affiche l’ordre d’appel des événements de durée Loadedde vie et Unloaded d’appel Initializedsur chaque objet d’arborescence. Ces événements sont décrits dans les sections suivantes, dans l’ordre dans lequel ils sont déclenchés sur chaque objet d’arborescence.

Événement de durée de vie initialisée

Le système d’événements WPF déclenche l’événement Initialized sur un élément :

  • Lorsque les propriétés de l’élément sont définies.
  • En même temps que l’objet est initialisé par le biais d’un appel à son constructeur.

Certaines propriétés d’élément, telles que Panel.Children, peuvent contenir des éléments enfants. Les éléments parents ne peuvent pas signaler l’initialisation tant que leurs éléments enfants ne sont pas initialisés. Par conséquent, les valeurs de propriété sont définies à partir des éléments imbriqués les plus profondément dans une arborescence d’éléments, suivis d’éléments parents successifs jusqu’à la racine de l’application. Étant donné que l’événement Initialized se produit lorsque les propriétés d’un élément sont définies, cet événement est d’abord appelé sur les éléments imbriqués les plus profondément imbriqués tels que définis dans le balisage, suivis d’éléments parents successifs jusqu’à la racine de l’application. Lorsque les objets sont créés dynamiquement dans le code-behind, leur initialisation peut être hors séquence.

Le système d’événements WPF n’attend pas que tous les éléments d’une arborescence d’éléments soient initialisés avant de déclencher l’événement Initialized sur un élément. Par conséquent, lorsque vous écrivez un gestionnaire d’événements Initialized pour n’importe quel élément, gardez à l’esprit que les éléments environnants dans l’arborescence logique ou visuelle, en particulier les éléments parents, n’ont peut-être pas été créés. Ou bien, leurs variables membres et liaisons de données peuvent être non initialisées.

Remarque

Lorsque l’événement Initialized est déclenché sur un élément, les utilisations de l’expression de l’élément, telles que les ressources dynamiques ou la liaison, sont non évaluées.

Événement de durée de vie chargée

Le système d’événements WPF déclenche l’événement Loaded sur un élément :

  • Lorsque l’arborescence logique qui contient l’élément est terminée et connectée à une source de présentation. La source de présentation fournit le handle de fenêtre (HWND) et la surface de rendu.
  • Lorsque la liaison de données à des sources locales, telles que d’autres propriétés ou sources de données directement définies, est terminée.
  • Une fois que le système de disposition a calculé toutes les valeurs nécessaires pour le rendu.
  • Avant le rendu final.

L’événement Loaded n’est déclenché sur aucun élément d’une arborescence d’éléments tant que tous les éléments de l’arborescence logique ne sont pas chargés. Le système d’événements WPF déclenche d’abord l’événement Loaded sur l’élément racine d’une arborescence d’éléments, puis sur chaque élément enfant successif jusqu’aux éléments imbriqués les plus profondément imbriqués. Bien que cet événement ressemble à un événement routé en tunneling , l’événement Loaded ne transporte pas les données d’événement d’un élément à un autre, de sorte que le marquage de l’événement comme géré n’a aucun effet.

Remarque

Le système d’événements WPF ne peut pas garantir que les liaisons de données asynchrones sont terminées avant l’événement Loaded . Les liaisons de données asynchrones sont liées à des sources externes ou dynamiques.

Événement de durée de vie déchargée

Le système d’événements WPF déclenche l’événement Unloaded sur un élément :

  • Lors de la suppression de sa source de présentation, ou
  • Lors de la suppression de son parent visuel.

Le système d’événements WPF déclenche d’abord l’événement Unloaded sur l’élément racine d’une arborescence d’éléments, puis sur chaque élément enfant successif jusqu’aux éléments imbriqués les plus profondément imbriqués. Bien que cet événement ressemble à un événement routé de tunneling , l’événement Unloaded ne propage pas les données d’événement de l’élément à l’élément, de sorte que le marquage de l’événement comme géré n’a aucun effet.

Lorsque l’événement Unloaded est déclenché sur un élément, il s’agit d’un élément parent ou d’un élément plus élevé dans l’arborescence logique ou visuelle. Unset signifie que les liaisons de données, les références de ressources et les styles d’un élément ne sont plus définis sur leur valeur d’exécution normale ou la dernière fois connue.

Autres événements de durée de vie

Du point de vue des événements de durée de vie, il existe quatre types principaux d’objets WPF : éléments en général, éléments de fenêtre, hôtes de navigation et objets d’application. Les événements , Loadedet Unloaded la Initializeddurée de vie s’appliquent à tous les éléments au niveau de l’infrastructure. D’autres événements de durée de vie s’appliquent spécifiquement aux éléments de fenêtre, aux hôtes de navigation ou aux objets d’application. Pour plus d’informations sur ces autres événements de durée de vie, consultez :

Voir aussi