Поделиться через


Как создать пользовательское маршрутизируемое событие (WPF .NET)

Разработчики приложений и авторы компонентов Windows Presentation Foundation (WPF) могут создавать пользовательские маршрутизируемые события для расширения функциональности событий среды CLR. Сведения о возможностях перенаправленных событий см. в разделе Почему использовать перенаправленные события. В этой статье рассматриваются основы создания пользовательского маршрутизируемого события.

Необходимые условия

В статье предполагается, что у вас есть базовые знания о маршрутизированных событиях, а также что вы прочитали обзор маршрутизированных событий. Чтобы следовать примерам в этой статье, это поможет вам, если вы знакомы с языком разметки расширяемых приложений (XAML) и узнаете, как писать приложения Windows Presentation Foundation (WPF).

Этапы маршрутизированного события

Ниже приведены основные действия по созданию перенаправленного события:

  1. Зарегистрируйте RoutedEvent, используя метод RegisterRoutedEvent.

  2. Вызов регистрации возвращает экземпляр RoutedEvent, известный как идентификатор маршрутизированного события, который содержит имя зарегистрированного события, стратегию маршрутизации событий, и другие сведения о событии. Назначьте идентификатор статическому полю только для чтения. По соглашению:

    • Идентификатор перенаправленного события с стратегией называется <event name>Event. Например, если имя события Tap, идентификатор должен быть назван TapEvent.
    • Идентификатор перенаправленного события с стратегией туннелирования называется Preview<event name>Event. Например, если имя события Tap, идентификатор должен быть назван PreviewTapEvent.
  3. Определите CLR , добавить и , удалить методы доступа к событиям. Без методов доступа к событиям CLR вы сможете добавлять или удалять обработчики событий только с помощью прямых вызовов методов UIElement.AddHandler и UIElement.RemoveHandler. С помощью аксессоров событий CLR вы получаете следующие механизмы назначения обработчика событий:

    • Для языка разметки расширяемых приложений (XAML) можно использовать синтаксис атрибутов для добавления обработчиков событий.
    • Для C# можно использовать операторы += и -= для добавления или удаления обработчиков событий.
    • Для VB можно использовать инструкции AddHandler и RemoveHandler для добавления или удаления обработчиков событий.
  4. Добавьте пользовательскую логику для запуска маршрутизированного события. Например, ваша логика может активировать событие на основе пользовательского ввода и состояния приложения.

Пример

В следующем примере реализуется класс CustomButton в пользовательской библиотеке элементов управления. Класс CustomButton, производный от Button:

  1. Регистрирует RoutedEvent с именем ConditionalClick с помощью метода RegisterRoutedEvent и задает стратегию во время регистрации.
  2. Назначает экземпляр RoutedEvent, возвращенный из вызова регистрации, статическому полю, доступному только для чтения, с именем ConditionalClickEvent.
  3. Определяет среду CLR добавить и удалить методы доступа к событиям.
  4. Добавляет пользовательскую логику для вызова настраиваемого маршрутизируемого события при щелчке по CustomButton и применении внешнего условия. Хотя в примере кода возбуждается маршрутизируемое событие ConditionalClick в переопределенном виртуальном методе OnClick, вы можете вызвать событие любым выбранным вами способом.
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

В примере содержится отдельное приложение WPF, использующее разметку XAML для добавления экземпляра CustomButton в StackPanel, а также назначение метода Handler_ConditionalClick в качестве обработчика событий ConditionalClick для элементов CustomButton и 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>

В коде программной части приложение WPF определяет метод обработчика событий Handler_ConditionalClick. Методы обработчика событий можно реализовать только в коде программной части.

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

Когда щёлкают по CustomButton:

  1. Событие маршрутизации ConditionalClick вызывается на CustomButton.
  2. Запускается обработчик событий Handler_ConditionalClick, подключенный к CustomButton.
  3. ConditionalClick маршрутизируемое событие проходит по дереву элементов до StackPanel1.
  4. Запускается обработчик событий Handler_ConditionalClick, подключенный к StackPanel1.
  5. Маршрутизируемое событие ConditionalClick поднимается вверх по дереву элементов, потенциально активируя другие обработчики событий ConditionalClick, прикрепленные к другим проходящим элементам.

Обработчик событий Handler_ConditionalClick получает следующие сведения о событии, вызвавшее его:

  • Объект отправителя, который является элементом, к которому подключен обработчик событий. sender будет CustomButton при первом запуске обработчика и StackPanel1 второй раз.
  • Объект RoutedEventArgs.Source, который является элементом, который первоначально вызвал событие. В этом примере Source всегда CustomButton.

Заметка

Ключевое различие между маршрутизированным событием и событием CLR заключается в том, что маршрутизированное событие проходит по дереву элементов, ища обработчики, тогда как событие CLR не проходит по дереву элементов, и обработчики могут подключаться только к исходному объекту, вызвавшему событие. В результате маршрутизируемое событие sender может быть любым элементом в дереве элементов.

Событие туннелирования можно создать так же, как и событие бублинга, за исключением того, что вы задали стратегию маршрутизации в вызове регистрации событий на Tunnel. Дополнительные сведения о событиях туннелирования см. в разделе о событиях ввода WPF.

См. также