Jak utworzyć niestandardowe zdarzenie kierowane (WPF .NET)

Deweloperzy aplikacji i autorzy składników programu Windows Presentation Foundation (WPF) mogą tworzyć niestandardowe zdarzenia kierowane w celu rozszerzenia funkcjonalności zdarzeń środowiska uruchomieniowego języka wspólnego (CLR). Aby uzyskać informacje na temat możliwości zdarzenia kierowanego, zobacz Dlaczego warto używać zdarzeń trasowanych. W tym artykule opisano podstawy tworzenia niestandardowego zdarzenia kierowanego.

Ważne

Dokumentacja przewodnika dla komputerów dla platform .NET 7 i .NET 6 jest w budowie.

Wymagania wstępne

W tym artykule przyjęto założenie, że masz podstawową wiedzę na temat zdarzeń kierowanych i zapoznasz się z omówieniem zdarzeń trasowanych. Aby postępować zgodnie z przykładami w tym artykule, warto zapoznać się z językiem Extensible Application Markup Language (XAML) i wiedzieć, jak pisać aplikacje programu Windows Presentation Foundation (WPF).

Kroki zdarzenia kierowanego

Podstawowe kroki tworzenia zdarzenia kierowanego to:

  1. Zarejestruj przy RoutedEvent użyciu RegisterRoutedEvent metody .

  2. Wywołanie rejestracji zwraca wystąpienie znane jako identyfikator zdarzenia kierowanego, który zawiera zarejestrowaną RoutedEvent nazwę zdarzenia, strategię routingu i inne szczegóły zdarzenia. Przypisz identyfikator do statycznego pola tylko do odczytu. Zgodnie z konwencją:

    • Identyfikator zdarzenia kierowanego ze strategią bubbling nosi nazwę <event name>Event. Jeśli na przykład nazwa zdarzenia to Tap identyfikator powinien mieć nazwę TapEvent.
    • Identyfikator zdarzenia kierowanego ze strategią tunelowania nosi nazwę Preview<event name>Event. Jeśli na przykład nazwa zdarzenia to Tap identyfikator powinien mieć nazwę PreviewTapEvent.
  3. Zdefiniuj metody dostępu do zdarzeń clR i usuń je. Bez akcesorów zdarzeń CLR będzie można dodawać lub usuwać programy obsługi zdarzeń tylko za pomocą wywołań bezpośrednich do UIElement.AddHandler metod i UIElement.RemoveHandler . Dzięki akcesorom zdarzeń CLR uzyskasz następujące mechanizmy przypisywania obsługi zdarzeń:

    • W przypadku rozszerzalnego języka znaczników aplikacji (XAML) można użyć składni atrybutów, aby dodać programy obsługi zdarzeń.
    • W języku C# można użyć += operatorów i -= do dodawania lub usuwania procedur obsługi zdarzeń.
    • W przypadku języka VB można użyć instrukcji AddHandler i RemoveHandler , aby dodać lub usunąć programy obsługi zdarzeń.
  4. Dodaj logikę niestandardową do wyzwalania zdarzenia kierowanego. Na przykład logika może wyzwolić zdarzenie na podstawie danych wejściowych użytkownika i stanu aplikacji.

Przykład

Poniższy przykład implementuje klasę CustomButton w niestandardowej bibliotece kontrolek. Klasa CustomButton , która pochodzi z klasy Button:

  1. Rejestruje RoutedEvent nazwę przy ConditionalClick użyciu RegisterRoutedEvent metody i określa strategię bubbling podczas rejestracji.
  2. Przypisuje wystąpienie zwrócone RoutedEvent z wywołania rejestracji do statycznego pola readonly o nazwie ConditionalClickEvent.
  3. Definiuje rozszerzenie CLR add and remove event accessors (Dodawanie i usuwanie akcesorów zdarzeń).
  4. Dodaje logikę niestandardową w celu podniesienia niestandardowego zdarzenia kierowanego po kliknięciu CustomButton elementu , a warunek zewnętrzny ma zastosowanie. Mimo że przykładowy kod zgłasza ConditionalClick zdarzenie kierowane z metody wirtualnej przesłoniętej OnClick , możesz zgłosić zdarzenie w dowolny sposób.
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

Przykład zawiera oddzielną aplikację WPF, która używa znaczników XAML w celu dodania wystąpienia elementu do StackPanelklasy , oraz przypisania Handler_ConditionalClick metody jako ConditionalClick procedury obsługi zdarzeń dla CustomButton elementów iStackPanel1.CustomButton

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

W kodzie aplikacja WPF definiuje metodę Handler_ConditionalClick obsługi zdarzeń. Metody obsługi zdarzeń można zaimplementować tylko w kodzie.

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

Po CustomButton kliknięciu:

  1. Zdarzenie ConditionalClick kierowane jest wywoływane w pliku CustomButton.
  2. Wyzwalana Handler_ConditionalClick jest procedura obsługi zdarzeń dołączona do CustomButton .
  3. Zdarzenie ConditionalClick kierowane przechodzi w górę drzewa elementów do StackPanel1.
  4. Wyzwalana Handler_ConditionalClick jest procedura obsługi zdarzeń dołączona do StackPanel1 .
  5. Zdarzenie ConditionalClick kierowane kontynuuje drzewo elementów potencjalnie wyzwalające inne ConditionalClick programy obsługi zdarzeń dołączone do innych elementów przechodzących.

Procedura Handler_ConditionalClick obsługi zdarzeń uzyskuje następujące informacje o zdarzeniu, które go wyzwoliło:

  • Obiekt nadawcy , czyli element, do którego jest dołączony program obsługi zdarzeń. Będzie sender to CustomButton pierwszy raz, gdy program obsługi zostanie uruchomiony, a StackPanel1 drugi raz.
  • RoutedEventArgs.Source Obiekt, który jest elementem, który pierwotnie wzbudził zdarzenie. W tym przykładzie parametr ma Source zawsze CustomButtonwartość .

Uwaga

Kluczową różnicą między zdarzeniem kierowanym a zdarzeniem CLR jest to, że zdarzenie kierowane przechodzi przez drzewo elementów, szukając procedur obsługi, podczas gdy zdarzenie CLR nie przechodzi przez drzewo elementów i programy obsługi mogą dołączać tylko do obiektu źródłowego, który wywołał zdarzenie. W związku z tym zdarzenie sender kierowane może być dowolnym elementem przechodzenia w drzewie elementów.

Zdarzenie tunelowania można utworzyć w taki sam sposób jak zdarzenie bubbling, z wyjątkiem ustawiania strategii routingu w wywołaniu rejestracji zdarzeń na Tunnelwartość . Aby uzyskać więcej informacji na temat zdarzeń tunelowania, zobacz Zdarzenia wejściowe WPF.

Zobacz też