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

XAML (Extensible Application Markup Language) define um componente de linguagem e um tipo de evento chamado de evento anexado. Os eventos anexados podem ser usados para definir um novo evento roteado em uma classe que não seja de elemento e gerar esse evento em qualquer elemento em sua árvore. Para fazer isso, você deve registrar o evento anexado como um evento roteado e fornecer um código de suporte específico que dê 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, é útil se você estiver familiarizado com XAML e souber como escrever aplicativos WPF.

Sintaxe de evento anexada

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 do evento.

A sintaxe de atributo XAML a seguir anexa o AquariumFilter_Clean manipulador do AquariumFilter.Clean evento anexado ao aquarium1 elemento:

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

Neste exemplo, o prefixo aqua: é necessário porque as AquariumFilter classes and 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 fazer isso, chame o AddHandler método no objeto ao qual o manipulador deve anexar e passe o identificador de evento e o manipulador como parâmetros para o método.

Como o WPF implementa eventos anexados

Os eventos anexados do WPF são implementados como eventos roteados com suporte de um RoutedEvent campo. Como resultado, os eventos anexados se propagam pela árvore de elementos depois de serem gerados. Geralmente, o objeto que gera o evento anexado, conhecido como origem do 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 origem 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 de recursos em que há uma abstração de nível de serviço. Por exemplo, o WPF usa eventos anexados habilitados pelas classes static Mouse or Validation . As classes que interagem ou usam um serviço podem interagir com um evento usando a 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 do WPF usa eventos anexados extensivamente. No entanto, quase todos esses eventos anexados são exibidos como eventos roteados não anexados equivalentes por meio de elementos base. Cada evento de entrada roteado é um membro da classe de elemento base e é apoiado por um "wrapper" de evento CLR. Você raramente usará ou manipulará eventos anexados diretamente. Por exemplo, é mais fácil manipular o evento anexado Mouse.MouseDown subjacente em um UIElement evento roteado equivalente UIElement.MouseDown do que usando a sintaxe de evento anexado em XAML ou code-behind.

Os eventos anexados servem a uma finalidade de arquitetura, permitindo a expansão futura de dispositivos de entrada. Por exemplo, um novo dispositivo de entrada só precisaria ser elevado Mouse.MouseDown para simular a entrada do mouse e não precisaria derivar de Mouse para fazer isso. Esse cenário envolve a manipulação de código do evento, já 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.

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

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. Os métodos são:

  • Um método Add<event name>Handler , 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 retornado. O método chama o método da AddHandler classe base, passando o evento roteado e o manipulador como argumentos. Esse método dá suporte à sintaxe de atributo XAML para anexar um manipulador de eventos a um elemento. Esse método também permite o acesso de código ao repositório do manipulador de eventos para o evento anexado.

  • Um método Handler de nome>de evento Remove<, 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 retornado. O método chama o método da RemoveHandler classe base, passando o evento roteado e o manipulador como argumentos. Esse método permite o acesso de código ao repositório do manipulador de eventos para o evento anexado.

O WPF implementa eventos anexados como eventos roteados porque o identificador para a é definido pelo sistema de RoutedEvent eventos do WPF. Além disso, o roteamento de um evento é uma extensão natural do conceito de nível de linguagem XAML de um evento anexado. Essa estratégia de implementação restringe a manipulação de eventos anexados a UIElement classes derivadas ou ContentElement classes derivadas, pois somente essas classes têm AddHandler implementações.

Por exemplo, o código a seguir define o evento anexado Clean AquariumFilter na classe owner, que não é uma classe de elemento. O código define o evento anexado como um evento roteado e implementa os métodos de acessador 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 RegisterRoutedEvent método que retorna o identificador de evento anexado é o mesmo método usado para registrar eventos roteados não anexados. Os eventos roteados anexados e não anexados são registrados em um repositório interno centralizado. Essa implementação do repositório de eventos habilita o conceito de "eventos como uma interface" discutido na visão geral de eventos roteados.

Ao contrário do "wrapper" de eventos CLR usado para fazer backup de eventos roteados não anexados, os métodos de acessador de 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 UIElement.AddHandler métodos and UIElement.RemoveHandler em uma instância passada 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 do WPF

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

Normalmente, seu código não precisará gerar nenhum evento anexado definido pelo WPF existente, pois esses eventos seguem o modelo conceitual geral de "serviço". Nesse modelo, as 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 de basear eventos anexados em eventos roteados, use o método para gerar um evento anexado UIElement.RaiseEvent em qualquer UIElement ou ContentElement. Ao gerar um evento roteado, esteja ele anexado ou não, você deve designar um elemento em sua árvore de elementos como a origem do evento. Essa fonte é então relatada como o RaiseEvent chamador. Por exemplo, para gerar 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 origem do evento.

Confira também