Compartilhar via


Eventos de ciclo de vida do objeto (WPF .NET)

Durante seu tempo de vida, todos os objetos no código gerenciado do Microsoft .NET passam pelas fases de criação, usoe destruição. O Windows Presentation Foundation (WPF) fornece notificação desses estágios à medida que ocorrem em um objeto, gerando eventos de ciclo de vida. Para elementos do nível do framework do WPF (objetos visuais), o WPF implementa os eventos de ciclo de vida Initialized, Loadede Unloaded. Os desenvolvedores podem usar esses eventos de tempo de vida como ganchos para operações code-behind que envolvem elementos. Este artigo descreve os eventos de tempo de vida para objetos visuais e, em seguida, apresenta outros eventos de tempo de vida que se aplicam especificamente a elementos de janela, hosts de navegação ou objetos de aplicativo.

Pré-requisitos

Este artigo pressupõe um conhecimento básico de como o layout do elemento WPF pode ser conceitualizado como uma árvore e que você leu visão geral de eventos roteados. Para seguir os exemplos neste artigo, ele ajuda se você estiver familiarizado com XAML (Extensible Application Markup Language) e saber como escrever aplicativos WPF.

Eventos de ciclo de vida para objetos visuais

Elementos de nível de estrutura do WPF derivam de FrameworkElement ou FrameworkContentElement. Os eventos de tempo de vida Initialized, Loadede Unloaded são comuns a todos os elementos de nível de estrutura do framework do WPF. O exemplo a seguir mostra uma árvore de elementos que é implementada principalmente em XAML. O XAML define um elemento pai Canvas que contém elementos aninhados, em que cada um usa a sintaxe de atributo XAML para anexar manipuladores de eventos de tempo de vida Initialized, Loadede Unloaded.

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

Um dos elementos XAML é um controle personalizado, que deriva de uma classe base que atribui manipuladores de eventos de ciclo de vida no 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.

A saída do programa mostra a ordem de invocação dos eventos de tempo de vida Initialized, Loadede Unloaded em cada objeto de árvore. Esses eventos são descritos nas seções a seguir, na ordem em que são gerados em cada objeto de árvore.

Evento de ciclo de vida inicializado

O sistema de eventos do WPF gera o evento Initialized em um elemento:

  • Quando as propriedades do elemento são definidas.
  • Ao mesmo tempo em que o objeto é inicializado por meio de uma chamada para seu construtor.

Algumas propriedades de elemento, como Panel.Children, podem conter elementos filho. Os elementos pai não podem relatar sua inicialização até que os elementos filho sejam inicializados. Portanto, os valores de propriedade são definidos começando com os elementos mais profundamente aninhados em uma árvore de elementos, seguidos por elementos pai sucessivos até a raiz do aplicativo. Como o evento Initialized ocorre quando as propriedades de um elemento são definidas, ele é invocado primeiramente nos elementos que estão mais profundamente aninhados, conforme definido na marcação, e depois em elementos pai sucessivos até a raiz do aplicativo. Quando os objetos são criados dinamicamente em code-behind, sua inicialização pode estar fora de sequência.

O sistema de eventos WPF não aguarda que todos os elementos em uma árvore de elementos sejam inicializados antes de gerar o evento Initialized em um elemento. Portanto, ao escrever um manipulador de eventos Initialized para qualquer elemento, tenha em mente que os elementos circundantes na árvore lógica ou visual, particularmente os elementos pai, talvez não tenham sido criados. Ou, suas variáveis de membro e associações de dados podem não ser inicializadas.

Nota

Quando o evento Initialized é gerado em um elemento, os usos de expressão do elemento, como recursos dinâmicos ou associação, não serão avaliados.

Evento de tempo de vida carregado

O sistema de eventos do WPF gera o evento Loaded em um elemento:

  • Quando a árvore lógica que contém o elemento é concluída e conectada a uma fonte de apresentação. A fonte da apresentação fornece o identificador de janela (HWND) e a superfície de renderização.
  • Quando a associação de dados a fontes locais, como outras propriedades ou fontes de dados definidas diretamente, é concluída.
  • Depois que o sistema de layout tiver calculado todos os valores necessários para renderização.
  • Antes da renderização final.

O evento Loaded não é gerado em nenhum elemento em uma árvore de elementos até que todos os elementos dentro da árvore lógica sejam carregados. O sistema de eventos WPF primeiro dispara o evento Loaded no elemento raiz de uma árvore de elementos e, em seguida, em cada elemento filho sucessivo até os elementos mais profundamente aninhados. Embora esse evento possa parecer um evento roteado por tunelamento , o evento Loaded não carrega dados de um elemento para outro, portanto, marcar o evento como tratado não tem efeito.

Nota

O sistema de eventos WPF não pode garantir que associações de dados assíncronas tenham sido concluídas antes do evento Loaded. Associações de dados assíncronas associam-se a fontes externas ou dinâmicas.

Evento de ciclo de vida descarregado

O sistema de eventos do WPF gera o evento Unloaded em um elemento:

  • Na remoção de sua fonte de apresentação ou
  • Na remoção de seu pai visual.

O sistema de eventos WPF aciona primeiro o evento Unloaded no elemento raiz de uma árvore de elementos e, em seguida, em cada elemento filho sucessivo até alcançar os elementos mais profundamente aninhados. Embora esse evento possa ser semelhante a um evento roteado de túnel , o evento Unloaded não propaga dados de evento de um elemento para outro, portanto, marcar o evento como tratado não tem efeito.

Quando o evento Unloaded é gerado em um elemento, ele é elemento pai ou qualquer elemento mais alto na árvore lógica ou visual pode já ter sido não definido. Desconfigurado significa que as associações de dados, as referências de recurso e os estilos de um elemento não estão mais definidos com seu valor normal ou último valor conhecido em tempo de execução.

Outros eventos da vida

Do ponto de vista dos eventos ao longo do tempo de vida, há quatro tipos principais de objetos do WPF: elementos em geral, elementos de janela, hosts de navegação e objetos de aplicativo. Os eventos de ciclo de vida Initialized, Loadede Unloaded se aplicam a todos os elementos de nível de estrutura. Outros eventos de ciclo de vida se aplicam especificamente a elementos de janela, hosts de navegação ou objetos de aplicativo. Para obter informações sobre esses outros eventos de tempo de vida, consulte:

Consulte também