Partilhar via


Como criar um evento roteado personalizado (WPF .NET)

Os desenvolvedores de aplicativos do Windows Presentation Foundation (WPF) e os autores de componentes podem criar eventos roteados personalizados para estender a funcionalidade dos eventos CLR (Common Language Runtime). Para obter informações sobre recursos de eventos roteados, consulte Por que usar eventos roteados. Este artigo aborda as noções básicas da criação de um evento roteado personalizado.

Pré-requisitos

O artigo pressupõe um conhecimento básico de eventos roteados e que você leu Visão geral de eventos roteados. Para seguir os exemplos neste artigo, é útil se você estiver familiarizado com XAML (Extensible Application Markup Language) e souber como escrever aplicativos WPF (Windows Presentation Foundation).

Etapas de evento roteadas

As etapas básicas para criar um evento roteado são:

  1. Registre um RoutedEvent usando o RegisterRoutedEvent método.

  2. A chamada de registro retorna uma RoutedEvent instância, conhecida como identificador de evento roteado, que contém o nome do evento registrado, a estratégia de roteamento e outros detalhes do evento. Atribua o identificador a um campo estático somente leitura. Por convenção:

    • O identificador de um evento roteado com uma estratégia de propagação é chamado <event name>Event. Por exemplo, se o nome do evento for Tap , o identificador deverá ser nomeado TapEvent.
    • O identificador de um evento roteado com uma estratégia de tunelamento é denominado Preview<event name>Event. Por exemplo, se o nome do evento for Tap , o identificador deverá ser nomeado PreviewTapEvent.
  3. Defina acessadores de evento de adição e remoção de CLR. Sem acessadores de eventos CLR, você só poderá adicionar ou remover manipuladores de eventos por meio de chamadas diretas para os UIElement.AddHandler métodos and UIElement.RemoveHandler . Com acessadores de eventos CLR, você obtém estes mecanismos de atribuição de manipulador de eventos:

    • Para XAML (Extensible Application Markup Language), você pode usar a sintaxe de atributo para adicionar manipuladores de eventos.
    • Para C#, você pode usar os += operadores and -= para adicionar ou remover manipuladores de eventos.
    • Para VB, você pode usar as instruções AddHandler e RemoveHandler para adicionar ou remover manipuladores de eventos.
  4. Adicione lógica personalizada para acionar seu evento roteado. Por exemplo, sua lógica pode disparar o evento com base na entrada do usuário e no estado do aplicativo.

Exemplo

O exemplo a seguir implementa a CustomButton classe em uma biblioteca de controle personalizada. A CustomButton classe, que deriva de Button:

  1. Registra um RoutedEvent nome ConditionalClick usando o método e especifica a estratégia de propagação durante o RegisterRoutedEvent registro.
  2. Atribui a RoutedEvent instância retornada da chamada de registro a um campo estático somente leitura chamado ConditionalClickEvent.
  3. Define acessadores de evento de adição e remoção de CLR.
  4. Adiciona lógica personalizada para gerar o evento roteado personalizado quando o é clicado CustomButton e uma condição externa se aplica. Embora o código de exemplo gere o ConditionalClick evento roteado de dentro do método virtual substituído OnClick , você pode gerar seu evento da maneira que escolher.
public class CustomButton : Button
{
    // Register a custom routed event using the Bubble routing strategy.
    public static readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent(
        name: "ConditionalClick",
        routingStrategy: RoutingStrategy.Bubble,
        handlerType: typeof(RoutedEventHandler),
        ownerType: typeof(CustomButton));

    // Provide CLR accessors for assigning an event handler.
    public event RoutedEventHandler ConditionalClick
    {
        add { AddHandler(ConditionalClickEvent, value); }
        remove { RemoveHandler(ConditionalClickEvent, value); }
    }

    void RaiseCustomRoutedEvent()
    {
        // Create a RoutedEventArgs instance.
        RoutedEventArgs routedEventArgs = new(routedEvent: ConditionalClickEvent);

        // Raise the event, which will bubble up through the element tree.
        RaiseEvent(routedEventArgs);
    }

    // For demo purposes, we use the Click event as a trigger.
    protected override void OnClick()
    {
        // Some condition combined with the Click event will trigger the ConditionalClick event.
        if (DateTime.Now > new DateTime())
            RaiseCustomRoutedEvent();

        // Call the base class OnClick() method so Click event subscribers are notified.
        base.OnClick();
    }
}
Public Class CustomButton
    Inherits Button

    ' Register a custom routed event with the Bubble routing strategy.
    Public Shared ReadOnly ConditionalClickEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        name:="ConditionalClick",
        routingStrategy:=RoutingStrategy.Bubble,
        handlerType:=GetType(RoutedEventHandler),
        ownerType:=GetType(CustomButton))

    ' Provide CLR accessors to support event handler assignment.
    Public Custom Event ConditionalClick As RoutedEventHandler

        AddHandler(value As RoutedEventHandler)
            [AddHandler](ConditionalClickEvent, value)
        End AddHandler

        RemoveHandler(value As RoutedEventHandler)
            [RemoveHandler](ConditionalClickEvent, value)
        End RemoveHandler

        RaiseEvent(sender As Object, e As RoutedEventArgs)
            [RaiseEvent](e)
        End RaiseEvent

    End Event

    Private Sub RaiseCustomRoutedEvent()

        ' Create a RoutedEventArgs instance.
        Dim routedEventArgs As New RoutedEventArgs(routedEvent:=ConditionalClickEvent)

        ' Raise the event, which will bubble up through the element tree.
        [RaiseEvent](routedEventArgs)

    End Sub

    ' For demo purposes, we use the Click event as a trigger.
    Protected Overrides Sub OnClick()

        ' Some condition combined with the Click event will trigger the ConditionalClick event.
        If Date.Now > New DateTime() Then RaiseCustomRoutedEvent()

        ' Call the base class OnClick() method so Click event subscribers are notified.
        MyBase.OnClick()

    End Sub
End Class

O exemplo inclui um aplicativo WPF separado que usa marcação XAML para adicionar uma instância de the CustomButton a um StackPanel, e atribuir o Handler_ConditionalClick método como o ConditionalClick manipulador de eventos para os CustomButton elementos and StackPanel1 .

<Window x:Class="CodeSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:WpfControl;assembly=WpfControlLibrary"
        Title="How to create a custom routed event" Height="100" Width="300">

    <StackPanel Name="StackPanel1" custom:CustomButton.ConditionalClick="Handler_ConditionalClick">
        <custom:CustomButton
            Name="customButton"
            ConditionalClick="Handler_ConditionalClick"
            Content="Click to trigger a custom routed event"
            Background="LightGray">
        </custom:CustomButton>
    </StackPanel>
</Window>

No code-behind, o aplicativo WPF define o Handler_ConditionalClick método do manipulador de eventos. Os métodos do manipulador de eventos só podem ser implementados no code-behind.

// The ConditionalClick event handler.
private void Handler_ConditionalClick(object sender, RoutedEventArgs e)
{
    string senderName = ((FrameworkElement)sender).Name;
    string sourceName = ((FrameworkElement)e.Source).Name;

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.");
}

// Debug output when CustomButton is clicked:
// Routed event handler attached to CustomButton,
//     triggered by the ConditionalClick routed event raised on CustomButton.
// Routed event handler attached to StackPanel1,
//     triggered by the ConditionalClick routed event raised on CustomButton.
' The ConditionalClick event handler.
Private Sub Handler_ConditionalClick(sender As Object, e As RoutedEventArgs)

    Dim sourceName As String = CType(e.Source, FrameworkElement).Name
    Dim senderName As String = CType(sender, FrameworkElement).Name

    Debug.WriteLine($"Routed event handler attached to {senderName}, " +
        $"triggered by the ConditionalClick routed event raised on {sourceName}.")

End Sub

' Debug output when CustomButton is clicked:
' Routed event handler attached to CustomButton,
'     triggered by the ConditionalClick routed event raised on CustomButton.
' Routed event handler attached to StackPanel1,
'     triggered by the ConditionalClick routed event raised on CustomButton.

Quando CustomButton é clicado:

  1. O ConditionalClick evento roteado é gerado em CustomButton.
  2. O Handler_ConditionalClick manipulador de eventos anexado é CustomButton disparado.
  3. O ConditionalClick evento roteado percorre a árvore de elementos até StackPanel1.
  4. O Handler_ConditionalClick manipulador de eventos anexado é StackPanel1 disparado.
  5. O ConditionalClick evento roteado continua na árvore de elementos, potencialmente acionando outros ConditionalClick manipuladores de eventos anexados a outros elementos percorridos.

O Handler_ConditionalClick manipulador de eventos obtém as seguintes informações sobre o evento que o acionou:

  • O objeto sender , que é o elemento ao qual o manipulador de eventos está anexado. Será sender CustomButton a primeira vez que o manipulador será executado e StackPanel1 a segunda vez.
  • O RoutedEventArgs.Source objeto, que é o elemento que originalmente gerou o evento. Neste exemplo, o Source é sempre CustomButton.

Observação

Uma diferença fundamental entre um evento roteado e um evento CLR é que um evento roteado percorre a árvore de elementos, procurando manipuladores, enquanto um evento CLR não atravessa a árvore de elementos e os manipuladores só podem anexar ao objeto de origem que gerou o evento. Como resultado, um evento sender roteado pode ser qualquer elemento percorrido na árvore de elementos.

Você pode criar um evento de túnel da mesma forma que um evento de propagação, exceto que você definirá a estratégia de roteamento na chamada de registro de evento como Tunnel. Para obter mais informações sobre eventos de túnel, consulte Eventos de entrada do WPF.

Confira também