Partilhar via


Visão geral de eventos anexados (WPF .NET)

O Extensible Application Markup Language (XAML) define um componente de linguagem e um tipo de evento chamado evento anexado. Os eventos anexados podem ser usados para definir um novo evento roteado em uma classe não-elemento e desencadear esse evento em qualquer elemento na sua árvore. Para fazer isso, deve registar o evento anexado como um evento encaminhado e fornecer um código de suporte específico que ofereça suporte à funcionalidade de evento anexado. Como os eventos anexados são registrados como eventos roteados, quando gerados em um elemento eles se propagam pela árvore de elementos.

Pré-requisitos

O artigo pressupõe um conhecimento básico de eventos roteados do Windows Presentation Foundation (WPF) e que você leu visão geral de eventos roteados e XAML no WPF. Para seguir os exemplos neste artigo, isso ajuda se você estiver familiarizado com XAML e souber como escrever aplicativos WPF.

Sintaxe do evento anexado

Na sintaxe XAML, um evento anexado é especificado por seu nome de evento e seu tipo de proprietário, na forma de <owner type>.<event name>. Como o nome do evento é qualificado com o nome de seu tipo de proprietário, a sintaxe permite que o evento seja anexado a qualquer elemento que possa ser instanciado. Essa sintaxe também é aplicável a manipuladores de eventos roteados regulares que se anexam a um elemento arbitrário ao longo da rota de evento.

A seguinte sintaxe de atributo XAML anexa o manipulador AquariumFilter_Clean ao evento AquariumFilter.Clean associado ao elemento aquarium1:

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

Neste exemplo, o prefixo aqua: é necessário porque as classes AquariumFilter e Aquarium existem em um namespace e assembly CLR (Common Language Runtime) diferente.

Você também pode anexar manipuladores para eventos anexados no "code-behind". Para tal, chame o método AddHandler no objeto ao qual o manipulador deve ser anexado e forneça o identificador de evento e o manipulador como argumentos para o método.

Como o WPF implementa eventos anexados

Os eventos anexados do WPF são implementados como eventos roteados apoiados por um campo RoutedEvent. Como resultado, os eventos anexados propagam-se pela árvore de elementos depois de serem desencadeados. Geralmente, o objeto que gera o evento anexado, conhecido como fonte de evento, é uma fonte de sistema ou serviço. As fontes de sistema ou serviço não são uma parte direta da árvore de elementos. Para outros eventos anexados, a fonte do evento pode ser um elemento na árvore, como um componente dentro de um controle composto.

Cenários de eventos anexados

No WPF, os eventos anexados são usados em determinadas áreas funcionais onde há uma abstração de nível de serviço. Por exemplo, o WPF faz uso de eventos anexados habilitados pelas classes estáticas Mouse ou Validation. As classes que interagem ou usam um serviço podem interagir com um evento usando sintaxe de evento anexado ou exibir o evento anexado como um evento roteado. A última opção faz parte de como uma classe pode integrar os recursos do serviço.

O sistema de entrada WPF usa eventos anexados extensivamente. No entanto, quase todos esses eventos anexados são apresentados como equivalentes a eventos encaminhados não anexados através dos elementos base. Cada evento de entrada roteado é um membro da classe de elemento base e é apoiado por um evento CLR "wrapper". Você raramente usará ou manipulará eventos anexados diretamente. Por exemplo, é mais fácil manipular o evento subjacente anexado Mouse.MouseDown em uma UIElement através do evento roteado equivalente UIElement.MouseDown do que usar a sintaxe de evento anexado no XAML ou no code-behind.

Os eventos anexados servem a um propósito de arquitetura, permitindo a expansão futura de dispositivos de entrada. Por exemplo, um novo dispositivo de entrada só precisaria levantar Mouse.MouseDown para simular a entrada do mouse, e não precisaria derivar de Mouse para fazê-lo. Esse cenário envolve a manipulação de código do evento, uma vez que a manipulação XAML do evento anexado não seria relevante.

Manipular um evento anexado

O processo para codificar e manipular um evento anexado é basicamente o mesmo que para um evento roteado não anexado.

Como observado anteriormente, os eventos anexados ao WPF existentes normalmente não se destinam a ser manipulados diretamente no WPF. Mais frequentemente, o objetivo de um evento anexado é permitir que um elemento dentro de um controle composto relate seu estado para um elemento pai dentro do controle. Nesse cenário, o evento é gerado no código e depende da manipulação da classe na classe parental relevante. Por exemplo, espera-se que os itens dentro de um Selector gerem o evento Selected anexado, que é então manipulado pela classe Selector. A classe Selector converte potencialmente o evento Selected no evento roteado SelectionChanged. Para obter mais informações sobre eventos encaminhados e manipulação de classes, consulte Marcar eventos encaminhados como manipulados e manipulação de classes.

Definir um evento anexado personalizado

Se você estiver derivando de classes base comuns do WPF, poderá implementar seu evento anexado personalizado incluindo dois métodos de acessador em sua classe. Esses métodos são:

  • Um Add<nome de evento>Handler método, com um primeiro parâmetro que é o elemento no qual o manipulador de eventos está anexado e um segundo parâmetro que é o manipulador de eventos a ser adicionado. O método deve ser public e static, sem valor de retorno. O método chama o método de classe base AddHandler, passando o evento roteado e o manipulador como argumentos. Esse método dá suporte à sintaxe do atributo XAML para anexar um manipulador de eventos a um elemento. Esse método também permite o acesso de código ao armazenamento do manipulador de eventos para o evento anexado.

  • Um Remove<nome de evento>Handler método, com um primeiro parâmetro que é o elemento no qual o manipulador de eventos está anexado e um segundo parâmetro que é o manipulador de eventos a ser removido. O método deve ser public e static, sem valor de retorno. O método chama o método de classe base RemoveHandler, passando o evento roteado e o manipulador como argumentos. Esse método permite o acesso de código ao armazenamento do manipulador de eventos para o evento anexado.

O WPF implementa eventos anexados como eventos roteados porque o identificador de um RoutedEvent é definido pelo sistema de eventos WPF. Além disso, direcionar um evento é uma extensão natural do conceito de evento anexado no contexto da linguagem XAML. Essa estratégia de implementação restringe a manipulação de eventos anexados apenas às classes derivadas de UIElement ou ContentElement, porque somente essas classes têm implementações de AddHandler.

Por exemplo, o código a seguir define o evento Clean anexado na classe proprietário do AquariumFilter, que não é uma classe de elemento. O código define o evento anexado como um evento roteado e implementa os métodos de acesso necessários.

public class AquariumFilter
{
    // Register a custom routed event using the bubble routing strategy.
    public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));

    // Provide an add handler accessor method for the Clean event.
    public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.AddHandler(CleanEvent, handler);
    }

    // Provide a remove handler accessor method for the Clean event.
    public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.RemoveHandler(CleanEvent, handler);
    }
}
Public Class AquariumFilter

    ' Register a custom routed event using the bubble routing strategy.
    Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))

    ' Provide an add handler accessor method for the Clean event.
    Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[AddHandler](CleanEvent, handler)
        End If
    End Sub

    ' Provide a remove handler accessor method for the Clean event.
    Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[RemoveHandler](CleanEvent, handler)
        End If
    End Sub

End Class

O método RegisterRoutedEvent que retorna o identificador de evento anexado é o mesmo método usado para registrar eventos roteados não anexados. Os eventos roteados ligados e não ligados são registados em um repositório interno centralizado. Essa implementação de armazenamento de eventos habilita o conceito de "eventos como uma interface" discutido em visão geral de eventos roteados.

Ao contrário do "wrapper" de eventos CLR usado para apoiar eventos roteados não anexados, os métodos de acesso a eventos anexados podem ser implementados em classes que não derivam de UIElement ou ContentElement. Isso é possível porque o código de suporte de evento anexado chama os métodos UIElement.AddHandler e UIElement.RemoveHandler em uma instância passada em UIElement. Por outro lado, o wrapper CLR para eventos roteados não anexados chama esses métodos diretamente na classe proprietária, de modo que a classe deve derivar de UIElement.

Gerar um evento anexado ao WPF

O processo para gerar um evento anexado é essencialmente o mesmo que para um evento enviado não anexado.

Normalmente, seu código não precisará gerar nenhum evento anexado definido pelo WPF existente, uma vez que esses eventos seguem o modelo conceitual geral de "serviço". Nesse modelo, classes de serviço, como InputManager, são responsáveis por gerar eventos anexados definidos pelo WPF.

Ao definir um evento anexado personalizado usando o modelo WPF para basear os eventos anexados em eventos roteados , use o método UIElement.RaiseEvent para desencadear um evento anexado em qualquer UIElement ou ContentElement. Ao gerar um evento roteado, esteja ele anexado ou não, é necessário designar um elemento na árvore de elementos como a fonte do evento. Essa fonte é então indicada como chamador RaiseEvent. Por exemplo, para acionar o evento roteado anexado AquariumFilter.Clean em aquarium1:

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

No exemplo anterior, aquarium1 é a fonte do evento.

Ver também