Подключенные события WPF против не подключенных событий

#c# #wpf #xaml #routedevent

#c# #wpf #xaml #routedevent

Вопрос:

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

Реализация

Класс ButtonBase объявляет маршрутизируемое событие с именем ClickEvent; обычное маршрутизируемое событие.

 public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ButtonBase));

[Category("Behavior")]
public event RoutedEventHandler Click
{
    add
    {
        base.AddHandler(ClickEvent, value);
    }
    remove
    {
        base.RemoveHandler(ClickEvent, value);
    }
}
  

Класс Mouse объявляет маршрутизируемое событие с именем MouseDownEvent; присоединенное событие.

 public static readonly RoutedEvent MouseDownEvent = EventManager.RegisterRoutedEvent("MouseDown", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(Mouse));

public static void AddMouseDownHandler(DependencyObject element, MouseButtonEventHandler handler)
{
    UIElement.AddHandler(element, MouseDownEvent, handler);
}

public static void RemoveMouseDownHandler(DependencyObject element, MouseButtonEventHandler handler)
{
    UIElement.RemoveHandler(element, MouseDownEvent, handler);
}
  

Оба события регистрируются в EventManager и сохраняются в виде общедоступных, статических полей, доступных только для чтения, одинаковым образом. ClickEvent имеет резервное поле события CLR с пользовательскими средствами добавления и удаления, которые вызывают base.AddHandler и base.RemoveHandler соответственно; оба из которых объявлены в базовом классе UIElement, от которого происходит ButtonBase. MouseDownEvent вместо этого имеет два статических метода AddMouseDownHandler и RemoveMouseDownHandler, которые в конечном итоге вызывают те же два метода AddHandler и RemoveHandler, объявленные в UIElement точно так же, как ClickEvent.

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


Использование

К обоим событиям могут быть прикреплены обработчики в XAML следующим образом:

 <Grid Button.Click="Grid_Click"
      Mouse.MouseDown="Grid_MouseDown">
</Grid>
  

Оба события могут быть присоединены в коде следующим образом:

 // Attach ClickEvent handler.
myGrid.AddHandler(Button.ClickEvent, new RoutedEventHandler(Grid_Click));

// Attach MouseDownEvent handler.
Mouse.AddMouseDownHandler(myGrid, Grid_MouseDown);
  

Как вы можете видеть, оба события могут быть присоединены к элементам, которые не являются их владельцами или не объявляют их.


Conclusion — What is an Attached Event?

MSDN documentation states:
http://msdn.microsoft.com/en-us/library/bb613550.aspx

Extensible Application Markup Language
(XAML) defines a language component
and type of event called an attached
event. The concept of an attached
event enables you to add a handler for
a particular event to an arbitrary
element rather than to an element that
actually defines or inherits the
event. In this case, neither the
object potentially raising the event
nor the destination handling instance
defines or otherwise «owns» the event.

In addition, the official MCTS Training Kit for Exam 70-511 — Windows Applications Development with Microsoft .NET Framework 4 states:

It is possible for a control to define
a handler for an event that the
control cannot itself raise. These
incidents are called attached events.
For example, consider Button controls
in a grid. The Button class defines a
Click event, but the Grid class does
not. However, you can still define a
handler for buttons in the grid by
attaching the Click event of the
Button control in the XAML code.

Термин «прикрепленное событие», похоже, размыт во всех учебных ресурсах Microsoft, хотя ясно, что здесь используются две разные, но очень тесно связанные концепции: прикрепленные события и синтаксис прикрепленных событий XAML. Оба источника Microsoft, которые я процитировал, похоже, ссылаются на синтаксис прикрепленных событий XAML, а не на фактические прикрепленные события. Однако на странице MSDN с обзором прикрепленных событий показано, как реализовать реальное прикрепленное событие, чего нет в обучающем наборе.

Мышь.MouseDownEvent является примером маршрутизируемого события, объявленного в статическом классе с соответствующими статическими обработчиками добавления и удаления, иначе известного как присоединенное событие. Однако ButtonBase.ClickEvent является обычным маршрутизируемым событием, хотя его все еще можно использовать с синтаксисом присоединенного события XAML таким же образом, как и фактическое присоединенное событие.

Цель фактического присоединенного события заключается в том, что оно позволяет разработчикам объявлять новые маршрутизируемые события для существующих классов, производных от UIElement, без необходимости их подклассирования; это означает, что вы можете просто присоединять новые маршрутизируемые события, не имея их на самом деле в классах, которые вы хотите создать или обработать. Но, подождите минутку … разве это не основная цель чистого маршрутизируемого события в первую очередь?

На странице обзора маршрутизируемых событий в MSDN указано:http://msdn.microsoft.com/en-us/library/ms742806.aspx

Функциональное определение: Маршрутизируемое событие — это тип события, которое может вызывать обработчики для нескольких прослушивателей в дереве элементов, а не только для объекта, который вызвал событие.

Из этого функционального определения кажется, что любое маршрутизируемое событие по существу обеспечивает ту же самую функциональность, что и подключенное событие. Таким образом, в основном присоединенное событие на самом деле является просто средством для объявления маршрутизируемого события в статическом классе и на самом деле не дает никаких преимуществ по сравнению с обычными маршрутизируемыми событиями.

Дайте мне знать, что вы думаете, поскольку я, возможно, здесь чего-то не хватает.

Спасибо, Тим Валентайн

Комментарии:

1. Присоединенное событие — это событие, которое может быть присоединено к любому объекту, а не только к объекту, который определяет событие. Маршрутизируемое событие — это событие, которое может быть перенаправлено обработчикам, не являющимся частью объекта. Событие может быть как маршрутизируемым, так и присоединенным событием. Например, Button.Click является присоединенным событием, потому что вы можете присоединить это событие к объектам, отличным от Button объекта. Это также маршрутизируемое событие, поскольку оно может обрабатываться несколькими Button.Click обработчиками событий в дереве пользовательского интерфейса, если вы не остановите это поведение, например, пометив событие как обработанное в одном из обработчиков

2. Кстати, этот вопрос прекрасно объясняет, как обрабатывать присоединенное событие из C #, а не из XAML. В большинстве мест показано последнее, а не первое (например, этот M $ docs , но также кулинарная книга WPF (и это очень хорошая книга!)).

3. Что касается вопроса, я ни в коем случае не эксперт, но разве присоединенное событие не является просто маршрутизируемым событием, обрабатываемым в элементе управления, где оно появилось, а не в исходном источнике? Тогда это были бы два названия для одного и того же объекта, просто применимые в разных контекстах.

Ответ №1:

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

В случае обычного маршрутизируемого события класс предоставляет интерфейс, позволяющий в какой-то момент отреагировать на событие, вызвав обработчик события. Но все, что нужно знать WPF, это является ли это объектом, производным от данного типа, и был ли зарегистрирован обработчик. Это означает, что мы можем создавать более простые иерархии классов, а также поддерживает принцип Открыто-закрыто (открыто для расширения, закрыто для модификации). Таким образом, программист может определить новое поведение, которое должно быть у нескольких классов, но не нуждается в изменении исходных классов.

Смотрите также Присоединенные свойства

Ответ №2:

Копирование комментария к ответу, чтобы он в конечном итоге не потерялся:

Присоединенное событие — это событие, которое может быть присоединено к любому объекту, а не только к объекту, определяющему событие.

Маршрутизируемое событие — это событие, которое может быть перенаправлено обработчикам, не являющимся частью объекта.

Событие может быть как маршрутизируемым, так и присоединенным событием. Например, Button.Click является присоединенным событием, потому что вы можете присоединить это событие к объектам, отличным от Button объекта. Это также маршрутизируемое событие, поскольку оно может обрабатываться несколькими Button.Click обработчиками событий в дереве пользовательского интерфейса, если вы не остановите это поведение, например, пометив событие как обработанное в одном из обработчиков.

(автор: Rachel 8 ’12 ноября в 20:39)