Compartir a través de


Creación de un evento enrutado personalizado

Los desarrolladores de aplicaciones y autores de componentes de Windows Presentation Foundation (WPF) pueden crear eventos enrutados personalizados para ampliar la funcionalidad de los eventos de Common Language Runtime (CLR). Para obtener información sobre las funcionalidades de eventos enrutados, vea Por qué usar eventos enrutados. En este artículo se describen los conceptos básicos de la creación de un evento enrutado personalizado.

Prerrequisitos

El artículo supone un conocimiento básico de los eventos enrutados y que hayas leído Información general sobre eventos enrutados. Para seguir los ejemplos de este artículo, le ayuda si está familiarizado con el lenguaje de marcado extensible de aplicaciones (XAML) y sabe cómo escribir aplicaciones de Windows Presentation Foundation (WPF).

Pasos de eventos enrutados

Los pasos básicos para crear un evento enrutado son:

  1. Registre un RoutedEvent mediante el RegisterRoutedEvent método .

  2. La llamada de registro devuelve una RoutedEvent instancia, conocida como identificador de evento enrutado, que contiene el nombre del evento registrado, la estrategia de enrutamiento y otros detalles del evento. Asigne el identificador a un campo de solo lectura estático. Por convención:

    • El identificador de un evento enrutado con una estrategia de burbujeo se denomina <event name>Event. Por ejemplo, si el nombre del evento es Tap , el identificador debe denominarse TapEvent.
    • El identificador de un evento enrutado con una estrategia de tunelización se denomina Preview<event name>Event. Por ejemplo, si el nombre del evento es Tap , el identificador debe denominarse PreviewTapEvent.
  3. Defina CLR add y remove accesores de eventos. Sin accesores de eventos CLR, solo podrá agregar o quitar controladores de eventos a través de llamadas directas a los métodos UIElement.AddHandler y UIElement.RemoveHandler. Con los descriptores de acceso de eventos CLR, obtendrá estos mecanismos para la asignación de controladores de eventos:

    • Para lenguaje de marcado de aplicaciones extensibles (XAML), puedes usar la sintaxis de atributo para agregar controladores de eventos.
    • Para C#, puede usar los += operadores y -= para agregar o quitar controladores de eventos.
    • Para VB, puede usar las instrucciones AddHandler y RemoveHandler para agregar o quitar controladores de eventos.
  4. Agregue lógica personalizada para activar su evento enrutado. Por ejemplo, la lógica podría desencadenar el evento en función de la entrada del usuario y el estado de la aplicación.

Ejemplo

En el ejemplo siguiente se implementa la CustomButton clase en una biblioteca de controles personalizada. La CustomButton clase , que deriva de Button:

  1. Registra un RoutedEvent denominado ConditionalClick usando el método RegisterRoutedEvent y especifica la estrategia de propagación durante el registro.
  2. Asigna la RoutedEvent instancia devuelta desde la llamada de registro a un campo estático de solo lectura denominado ConditionalClickEvent.
  3. Define los descriptores de acceso de eventos de CLR add y remove.
  4. Agrega lógica personalizada para activar el evento enrutado personalizado cuando se hace clic en CustomButton y se cumple una condición externa. Aunque el código de ejemplo genera el ConditionalClick evento enrutado desde dentro del método virtual invalidado OnClick , puede generar el evento de cualquier manera que elija.
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

En el ejemplo se incluye una aplicación WPF independiente que usa el marcado XAML para agregar una instancia de CustomButton a StackPanel, y para asignar el método Handler_ConditionalClick como controlador de eventos ConditionalClick para los elementos CustomButton y 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>

En el código subyacente, la aplicación WPF define el Handler_ConditionalClick método de controlador de eventos. Los métodos del controlador de eventos solo se pueden implementar en código subyacente.

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

Al hacer clic en CustomButton:

  1. El ConditionalClick evento enrutado se genera en CustomButton.
  2. El Handler_ConditionalClick controlador de eventos asociado a CustomButton se desencadena.
  3. El ConditionalClick evento enrutado atraviesa el árbol de elementos a StackPanel1.
  4. El Handler_ConditionalClick controlador de eventos asociado a StackPanel1 se desencadena.
  5. El ConditionalClick evento enrutado continúa hacia arriba en el árbol de elementos, potencialmente desencadenando otros ConditionalClick controladores de eventos asociados a otros elementos recorridos.

El Handler_ConditionalClick controlador de eventos obtiene la siguiente información sobre el evento que lo desencadenó:

  • Objeto remitente , que es el elemento al que está asociado el controlador de eventos. El valor de sender será CustomButton la primera vez que se ejecute el controlador y StackPanel1 la segunda.
  • Objeto RoutedEventArgs.Source , que es el elemento que generó originalmente el evento. En este ejemplo, el Source siempre es CustomButton.

Nota:

Una diferencia clave entre un evento enrutado y un evento CLR es que un evento enrutado atraviesa el árbol de elementos, buscando controladores, mientras que un evento CLR no atraviesa el árbol de elementos y los controladores solo pueden asociarse al objeto de origen que generó el evento. Como resultado, un evento sender enrutado puede ser cualquier elemento recorrido en el árbol de elementos.

Puede crear un evento de tunelización del mismo modo que un evento de propagación, salvo que establecerá la estrategia de enrutamiento en la llamada de registro de eventos a Tunnel. Para obtener más información sobre los eventos de tunelización, vea Eventos de entrada de WPF.

Consulte también