Общие сведения о присоединенных событиях (WPF .NET)

Расширяемый язык разметки приложений (XAML) определяет языковой компонент и тип события, называемый присоединенным событием. Присоединенные события можно использовать для определения нового перенаправленного события в классе, отличном от элемента, и вызвать это событие на любом элементе в дереве. Для этого необходимо зарегистрировать присоединенное событие в качестве перенаправленного события и предоставить конкретный код резервной копии, поддерживающий функции присоединенного события. Так как присоединенные события регистрируются как перенаправленные события, при возникновении элемента, который они распространяются через дерево элементов.

Важно!

Документация по рабочему столу для .NET 7 и .NET 6 находится в стадии разработки.

Необходимые компоненты

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

Синтаксис присоединенного события

В синтаксисе XAML присоединенное событие указывается именем события и его типом владельца в виде <owner type>.<event name>. Так как имя события квалифицировано с именем своего типа владельца, синтаксис позволяет присоединить событие к любому элементу, который можно создать. Этот синтаксис также применим к обработчикам регулярных перенаправленных событий, которые присоединяются к произвольному элементу вдоль маршрута событий.

Следующий синтаксис атрибута XAML подключает AquariumFilter_Clean обработчик для присоединенного AquariumFilter.Clean события к элементу aquarium1 :

<aqua:Aquarium x:Name="aquarium1" Height="300" Width="400" aqua:AquariumFilter.Clean="AquariumFilter_Clean"/>

В этом примере префикс необходим, aqua: так как AquariumFilterAquarium классы существуют в другом пространстве имен среды CLR и сборке.

Вы также можете присоединить обработчики для присоединенных событий в коде за ним. Для этого вызовите AddHandler метод объекта, к которому обработчик должен подключиться и передать идентификатор события и обработчик в качестве параметров в метод.

Как WPF реализует присоединенные события

Присоединенные события WPF реализуются как перенаправленные события, поддерживаемые полем RoutedEvent . В результате присоединенные события распространяются через дерево элементов после их создания. Как правило, объект, который вызывает присоединенное событие, известное как источник событий, является системой или источником службы. Системные или служебные источники не являются прямой частью дерева элементов. Для других присоединенных событий источник событий может быть элементом в дереве, например компонентом в составном элементе управления.

Сценарии присоединенных событий

В WPF присоединенные события используются в определенных областях функций, где есть абстракция уровня обслуживания. Например, WPF использует присоединенные события, включенные статическими Mouse или Validation классами. Классы, взаимодействующие с службой или использующие ее, могут взаимодействовать с событием с помощью синтаксиса присоединенного события или отображать присоединенное событие как перенаправленное событие. Последний вариант является частью того, как класс может интегрировать возможности службы.

Система ввода WPF широко использует вложенные события. Однако почти все эти присоединенные события отображаются как эквивалентные несоединяемые перенаправленные события через базовые элементы. Каждое перенаправленное входное событие является членом базового класса элементов и поддерживается событием CLR "оболочка". Вы редко используете или обрабатываете присоединенные события напрямую. Например, проще обрабатывать базовое присоединенное Mouse.MouseDown событие через UIElement эквивалентное UIElement.MouseDown перенаправленное событие, чем с помощью синтаксиса присоединенного события в XAML или коде.

Присоединенные события служат цели архитектуры, обеспечивая дальнейшее расширение устройств ввода. Например, новое устройство ввода потребуется Mouse.MouseDown только для имитации входных данных мыши, и это не потребуется для этого.Mouse Этот сценарий включает обработку кода события, так как обработка xaml присоединенного события не будет релевантной.

Обработка присоединенного события

Процесс написания кода и обработки присоединенного события в основном совпадает с процессом, не подключенным к маршрутивному событию.

Как отмечалось ранее, существующие подключенные события WPF обычно не предназначены для непосредственной обработки в WPF. Чаще всего присоединенное событие позволяет элементу в составном элементе управления сообщать о его состоянии родительскому элементу в элементе управления. В этом сценарии событие вызывается в коде и зависит от обработки классов в соответствующем родительском классе. Например, элементы внутри объекта Selector должны вызывать Selected присоединенное событие, которое затем обрабатывается классом Selector . Класс Selector потенциально преобразует Selected событие в SelectionChanged перенаправленное событие. Дополнительные сведения о перенаправленных событиях и обработке классов см. в разделе "Маркировка перенаправленных событий как обработанные" и "Обработка классов".

Определение настраиваемого присоединенного события

Если вы используете общие базовые классы WPF, вы можете реализовать пользовательское присоединенное событие, включив два метода доступа в класс. Эти методы:

  • Метод Обработчика имени>события add<, с первым параметром, который является элементом, на котором подключен обработчик событий, и второй параметр, добавляемый обработчиком событий. Метод должен быть public и static, без возвращаемого значения. Метод вызывает AddHandler метод базового класса, передавая перенаправленное событие и обработчик в качестве аргументов. Этот метод поддерживает синтаксис атрибута XAML для присоединения обработчика событий к элементу. Этот метод также обеспечивает доступ кода к хранилищу обработчика событий для присоединенного события.

  • Метод Remove<name>Handler с первым параметром, который является элементом, на котором подключен обработчик событий, и вторым параметром, который требуется удалить обработчиком событий. Метод должен быть public и static, без возвращаемого значения. Метод вызывает RemoveHandler метод базового класса, передавая перенаправленное событие и обработчик в качестве аргументов. Этот метод обеспечивает доступ кода к хранилищу обработчика событий для присоединенного события.

WPF реализует присоединенные события в качестве перенаправленных событий, так как идентификатор для RoutedEvent события определяется системой событий WPF. Кроме того, маршрутизация события — это естественное расширение концепции языка XAML для присоединенного события. Эта стратегия реализации ограничивает обработку присоединенных событий UIElement производными классами или ContentElement производными классами, так как только эти классы имеют AddHandler реализации.

Например, следующий код определяет присоединенное Clean событие для AquariumFilter класса владельца, который не является классом элементов. Код определяет присоединенное событие как перенаправленное событие и реализует необходимые методы доступа.

public class AquariumFilter
{
    // Register a custom routed event using the bubble routing strategy.
    public static readonly RoutedEvent CleanEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));

    // Provide an add handler accessor method for the Clean event.
    public static void AddCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.AddHandler(CleanEvent, handler);
    }

    // Provide a remove handler accessor method for the Clean event.
    public static void RemoveCleanHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
    {
        if (dependencyObject is not UIElement uiElement)
            return;

        uiElement.RemoveHandler(CleanEvent, handler);
    }
}
Public Class AquariumFilter

    ' Register a custom routed event using the bubble routing strategy.
    Public Shared ReadOnly CleanEvent As RoutedEvent = EventManager.RegisterRoutedEvent(
        "Clean", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))

    ' Provide an add handler accessor method for the Clean event.
    Public Shared Sub AddCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[AddHandler](CleanEvent, handler)
        End If
    End Sub

    ' Provide a remove handler accessor method for the Clean event.
    Public Shared Sub RemoveCleanHandler(dependencyObject As DependencyObject, handler As RoutedEventHandler)
        Dim uiElement As UIElement = TryCast(dependencyObject, UIElement)

        If uiElement IsNot Nothing Then
            uiElement.[RemoveHandler](CleanEvent, handler)
        End If
    End Sub

End Class

Метод RegisterRoutedEvent , возвращающий присоединенный идентификатор события, является тем же методом, который используется для регистрации несоединяемых перенаправленных событий. Подключенные и не подключенные маршрутируемые события регистрируются в централизованном внутреннем хранилище. Эта реализация хранилища событий включает концепцию "события в качестве интерфейса", описанную в обзоре событий Routed.

В отличие от события СРЕДЫ CLR , используемого для возврата не подключенных перенаправленных событий, методы доступа к присоединенным событиям могут быть реализованы в классах, которые не являются производными от UIElement или ContentElement. Это возможно, так как присоединенный код резервного копирования событий вызывает UIElement.AddHandler и UIElement.RemoveHandler методы переданного экземпляра UIElement . В отличие от этого, оболочка СРЕДЫ CLR для не присоединенных событий вызывает эти методы непосредственно в собственном классе, чтобы класс должен быть производным от UIElement.

Создание присоединенного события WPF

Процесс вызова присоединенного события по сути совпадает с процессом, не подключенным к перенаправленному событию.

Как правило, код не должен вызывать существующие события, определенные WPF, так как эти события соответствуют общей концептуальной модели "service". В этой модели классы служб, такие как InputManager, отвечают за создание присоединенных событий WPF.

При определении настраиваемого присоединенного события с помощью модели WPF базирования присоединенных событий на перенаправленных событиях используйте UIElement.RaiseEvent метод для вызова присоединенного события на любом UIElement или ContentElement. При вызове перенаправленного события, присоединенного или нет, необходимо назначить элемент в дереве элементов в качестве источника событий. Затем этот источник сообщается как вызывающий RaiseEvent объект. Например, чтобы вызвать присоединенное AquariumFilter.Clean перенаправленное событие в aquarium1:

aquarium1.RaiseEvent(new RoutedEventArgs(AquariumFilter.CleanEvent));
aquarium1.[RaiseEvent](New RoutedEventArgs(AquariumFilter.CleanEvent))

В предыдущем примере aquarium1 — источник событий.

См. также