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


Общие сведения о вложенных событиях

Extensible Application Markup Language (XAML) определяет компонент языка и тип события, называемый вложенным событием. Концепция вложенных событий позволяет вам добавить обработчик для конкретного события к произвольному элементу, а не к элементу, который в настоящее время определяет или наследует событие. В этом случае ни объект, потенциально вызывающий событие, ни экземпляр класса, обрабатывающий назначение, не определяет или как-нибудь иначе не "владеет" событием.

В этом разделе содержатся следующие подразделы.

  • Предварительные требования
  • Синтаксис вложенного события
  • Как WPF реализовывает вложенные события
  • Сценарии для вложенных событий
  • Обработка вложенного события в WPF
  • Определение собственных вложенных событий в качестве событий маршрутизации
  • Создание вложенного события WPF
  • Связанные разделы

Предварительные требования

В этом разделе предполагается, что вы прочитали Общие сведения о перенаправленных событиях и Общие сведения о языке XAML (WPF).

Синтаксис вложенного события

Вложенные события имеют синтаксис XAML и шаблон кодирования, который должен использоваться фоновым кодом, чтобы поддерживать использование вложенных событий.

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

Например, ниже приведен синтаксис XAML для присоединения обработчика для пользовательского вложенного события NeedsCleaning.

<aqua:Aquarium Name="theAquarium" Height="600" Width="800" aqua:AquariumFilter.NeedsCleaning="WashMe"/>

Обратите внимание на префикс aqua:; префикс в этом случае необходим, поскольку вложенное событие является пользовательским событием, которое поступает из пользовательских сопоставленных xmlns.

Как WPF реализовывает вложенные события

В WPF вложенные события содержатся в поле RoutedEvent и направляются через дерево, после чего они вызываются. Обычно источник вложенного события (объект, который вызывает событие) является системным или служебным источником, а объект, который запускает код, вызывающий событие, напрямую не является частью дерева элементов.

Сценарии для вложенных событий

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

Хотя WPF определяет количество вложенных событий, скриптов, в которых вы будете либо использовать, либо непосредственно обрабатывать присоединенное событие, очень мало. Как правило, вложенное событие служит архитектурной цели, но затем передается неприсоединенному (прикреплен с "оболочкой" события CLR) событию маршрутизации.

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

Обработка вложенного события в WPF

Процесс для обработки вложенных событий и код обработчика, который вы будете писать, по существу такой же, как и для события маршрутизации.

В общем случае вложенное событие WPF не очень сильно отличается от события маршрутизации WPF. Различия в том, как событие привязывается и как оно представляется классом в качестве члена (что также влияет на синтаксис обработчика XAML).

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

Определение собственных вложенных событий в качестве событий маршрутизации

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

Шаблон выглядит следующим образом.

  • Метод Add*Handler с двумя параметрами. Первый параметр должен определять событие, и у идентифицированного события должны совпадать имена со * в имени метода. Вторым параметром является обработчик для добавления. Метод должен быть открытым и статическим, без возвращаемого значения.

  • Метод Remove*Handler с двумя параметрами. Первый параметр должен определять событие, и у идентифицированного события должны совпадать имена со * в имени метода. Вторым параметром является обработчик для удаления. Метод должен быть открытым и статическим, без возвращаемого значения.

Метод доступа Add*Handler упрощает обработку XAML, когда атрибуты вложенного обработчика событий объявлены в элементе. Методы Add*Handler и Remove*Handler также разрешают доступ кода к хранилищу обработчика событий для вложенного события.

Этого общего шаблона еще не достаточно для практической реализации на платформе .NET Framework, так как любая данная реализация чтения XAML может иметь различные схемы для идентификации основных событий в поддерживаемом языке и архитектуре. Это является одной из причин, по которой WPF реализует вложенные события в качестве перенаправленных событий; идентификатор, используемый для события (RoutedEvent), уже определен системой событий WPF. К тому же маршрутизация события является расширением естественной реализации в понятиях на уровне языка XAML вложенного события.

Реализация Add*Handler для вложенного события WPF состоит из вызова AddHandler с перенаправленным событием и обработчиком в качестве аргументов.

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

Например, следующий код определяет вложенное событие NeedsCleaning в собственном классе Aquarium, используя стратегию присоединенных событий WPF объявления присоединенного события в качестве события с маршрутизацией.

Public Shared ReadOnly NeedsCleaningEvent As RoutedEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(AquariumFilter))
Public Shared Sub AddNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
Public Shared Sub RemoveNeedsCleaningHandler(ByVal d As DependencyObject, ByVal handler As RoutedEventHandler)
    Dim uie As UIElement = TryCast(d, UIElement)
    If uie IsNot Nothing Then
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler)
    End If
End Sub
public static readonly RoutedEvent NeedsCleaningEvent = EventManager.RegisterRoutedEvent("NeedsCleaning", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AquariumFilter));
public static void AddNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.AddHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}
public static void RemoveNeedsCleaningHandler(DependencyObject d, RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
        uie.RemoveHandler(AquariumFilter.NeedsCleaningEvent, handler);
    }
}

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

Создание вложенного события WPF

Обычно вам необязательно вызывать существующие вложенные события, определенные WPF, из своего кода. Эти события следуют общей концептуальной модели "службы", и классы служб, такие как InputManager, ответственны за вызов событий.

Однако при определении пользовательского вложенного события на основе модели WPF, основанной на вложенных событиях в RoutedEvent, вы можете использовать RaiseEvent для вызова присоединенного события из любогоUIElement или ContentElement. Вызов перенаправленного события (вложенного или нет) требует объявления конкретного элемента в дереве элементов в качестве источника события; этот источник указывается в качестве вызывающего RaiseEvent. Определение, какой элемент описывается как источник в дереве, является обязанностью вашей службы

См. также

Основные понятия

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

Подробное описание синтаксиса XAML

Код XAML и пользовательские классы для WPF