Gewusst wie: Erstellen eines benutzerdefinierten Routingereignisses (WPF .NET)

Windows Presentation Foundation (WPF)-Anwendungsentwickler und Komponentenautoren können benutzerdefinierte weitergeleitete Ereignisse erstellen, um die Funktionalität der Ereignisse für allgemeine Sprachlaufzeit (CLR) zu erweitern. Informationen zu Routingereignisfunktionen finden Sie unter Warum routingfähige Ereignisse verwenden. Dieser Artikel behandelt die Grundlagen der Erstellung eines benutzerdefinierten weitergeleiteten Ereignisses.

Wichtig

Der Desktopleitfaden zu .NET 7 und .NET 6 ist in Bearbeitung.

Voraussetzungen

Im Artikel wird davon ausgegangen, dass Sie grundlegende Kenntnisse über Routingereignisse besitzen und die Übersicht über Routingereignisse gelesen haben. Um den Beispielen in diesem Artikel zu folgen, ist es hilfreich, wenn Sie mit Extensible Application Markup Language (XAML) vertraut sind und wissen, wie Windows Presentation Foundation-Anwendungen (WPF-Anwendungen) geschrieben werden.

Weitergeleitete Ereignisschritte

Die grundlegenden Schritte zum Erstellen eines weitergeleiteten Ereignisses sind:

  1. Registrieren Sie eine RoutedEvent mit der RegisterRoutedEvent-Methode.

  2. Der Registrierungsaufruf gibt eine RoutedEvent-Instanz zurück, die als Routed-Ereignisbezeichner bezeichnet wird, der den registrierten Ereignisnamen, die Routingstrategie und andere Ereignisdetails enthält. Weisen Sie den Bezeichner einem statischen Readonly-Feld zu. Nach Konvention:

    • Der Bezeichner für ein weitergeleitetes Ereignis mit einer Bubbling-Strategie wird benannt <event name>Event. Wenn der Ereignisname z. B. der Name des Ereignisses ist Tap, sollte der Bezeichner TapEvent benannt werden.
    • Der Bezeichner für ein weitergeleitetes Ereignis mit einer Tunnelstrategie wird benannt Preview<event name>Event. Wenn der Ereignisname z. B. der Name des Ereignisses ist Tap, sollte der Bezeichner PreviewTapEvent benannt werden.
  3. Definieren Sie CLR-Add - und Remove-Ereigniszugriffer . Ohne CLR-Ereigniszugriffer können Sie nur Ereignishandler über direkte Aufrufe der UIElement.AddHandler- und UIElement.RemoveHandler-Methoden hinzufügen oder entfernen. Mit CLR-Ereigniszugriffern erhalten Sie diese Ereignishandlerzuweisungsmechanismen:

    • Für Extensible Application Markup Language (XAML) können Sie Attributsyntax verwenden, um Ereignishandler hinzuzufügen.
    • Für C#können Sie die +=- und die -=-Operatoren verwenden, um Ereignishandler hinzuzufügen oder zu entfernen.
    • Für VB können Sie die AddHandler- und RemoveHandler-Anweisungen verwenden, um Ereignishandler hinzuzufügen oder zu entfernen.
  4. Fügen Sie benutzerdefinierte Logik hinzu, um das Routed-Ereignis auszulösen. Ihre Logik kann z. B. das Ereignis basierend auf benutzereingaben und Anwendungsstatus auslösen.

Beispiel

Im folgenden Beispiel wird die CustomButton-Klasse in einer benutzerdefinierten Steuerelementbibliothek implementiert. Die CustomButton-Klasse, von Button abgeleitet wird.

  1. Registriert einen RoutedEvent-Namen ConditionalClick mithilfe der Methode und gibt die RegisterRoutedEventBubbling-Strategie während der Registrierung an.
  2. Weist die Instanz, die RoutedEvent vom Registrierungsaufruf zurückgegeben wurde, einem statischen Readonly-Feld namens ConditionalClickEvent zu.
  3. Definieren Sie CLR-Add - und Remove-Ereigniszugriffer .
  4. Fügt benutzerdefinierte Logik hinzu, um das benutzerdefinierte routed-Ereignis zu auslösen, wenn die CustomButton-Option geklickt wird und eine externe Bedingung angewendet wird. Obwohl der Beispielcode das ConditionalClick weitergeleitete Ereignis aus der überschriebenen OnClick virtuellen Methode auslöst, können Sie Ihr Ereignis auf jede Weise auslösen, die Sie auswählen.
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

Das Beispiel enthält eine separate WPF-Anwendung, die XAML-Markup verwendet, um eine Instanz des CustomButton Elements StackPanelhinzuzufügen und die Handler_ConditionalClick Methode als ConditionalClick Ereignishandler für die CustomButton elemente StackPanel1 zuzuweisen.

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

In Codebehind definiert die WPF-Anwendung die Handler_ConditionalClick Ereignishandlermethode. Ereignishandlermethoden können nur in Codebehind implementiert werden.

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

Wenn CustomButton geklickt wurde:

  1. Das Routingereignis ConditionalClick wird auf CustomButtonausgelöst.
  2. Der Handler_ConditionalClick-Ereignishandler, der an CustomButton angehängt wurde, wird ausgelöst.
  3. Das ConditionalClick-Routingereignis durchläuft die Elementstruktur auf StackPanel1.
  4. Der Handler_ConditionalClick-Ereignishandler, der an StackPanel1 angehängt wurde, wird ausgelöst.
  5. Das ConditionalClick-Routingereignis führt die Elementstruktur aus, die möglicherweise andere ConditionalClick-Ereignishandler auslösen, die an andere durchlaufene Elemente angefügt sind.

Der Handler_ConditionalClick-Ereignishandler ruft die folgenden Informationen zum Ereignis ab, das sie ausgelöst hat:

  • Das Absenderobjekt , das das Element ist, an das der Ereignishandler angefügt ist. sender ist CustomButton, wenn der Handler das erste Mal ausgeführt wird, und StackPanel1 das zweite Mal.
  • Das RoutedEventArgs.Source-Objekt, das das Element ist, das das Ereignis ursprünglich ausgelöst hat. In diesem Beispiel ist Source immer CustomButton.

Hinweis

Ein wichtiger Unterschied zwischen einem routed-Ereignis und einem CLR-Ereignis besteht darin, dass ein weitergeleitetes Ereignis die Elementstruktur durchläuft und nach Handlern sucht, während ein CLR-Ereignis die Elementstruktur und Handler nicht durchlaufen, kann nur an das Quellobjekt angefügt werden, das das Ereignis ausgelöst hat. Daher kann ein weitergeleitetes Ereignis sender jedes durchlaufene Element in der Elementstruktur sein.

Sie können ein Tunneling-Ereignis auf dieselbe Weise wie ein Bubbling-Ereignis erstellen, außer sie legen die Routingstrategie im Ereignisregistrierungsaufruf fest Tunnel. Weitere Informationen zu Tunnelereignissen finden Sie unter WPF-Eingabeereignisse.

Siehe auch