Подключенные события WPF против не прикрепленных событий
Вопрос в том, что после всех моих исследований я все еще не могу найти разницу между обычным перенаправленным событием и прикрепленным событием. В чем функциональная разница? или другие согласны, что их нет?
Реализация
Класс 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);
Как видите, оба события могут быть прикреплены к элементам, которые не владеют ими или не объявляют их.
Вывод - что такое прикрепленное событие?
Документация MSDN гласит: http://msdn.microsoft.com/en-us/library/bb613550.aspx
Расширяемый язык разметки приложений (XAML) определяет языковой компонент и тип события, называемого присоединенным событием. Концепция присоединенного события позволяет вам добавить обработчик для определенного события в произвольный элемент, а не в элемент, который фактически определяет или наследует событие. В этом случае ни объект, потенциально вызывающий событие, ни экземпляр пункта назначения не определяют или иначе "владеют" событием.
Кроме того, официальный учебный комплект MCTS для экзамена 70-511 - Разработка приложений для Windows с использованием Microsoft .NET Framework 4 гласит:
Элемент управления может определить обработчик для события, которое сам элемент управления не может вызвать. Эти инциденты называются прикрепленными событиями. Например, рассмотрим элементы управления Button в сетке. Класс Button определяет событие Click, а класс Grid - нет. Однако вы все равно можете определить обработчик для кнопок в сетке, добавив событие Click элемента управления Button в код XAML.
Термин "присоединенное событие", кажется, расплывчатый во всех учебных ресурсах Microsoft, хотя ясно, что здесь действуют две разные, но очень тесно связанные концепции: присоединенные события и синтаксис присоединенных событий XAML. Оба источника Microsoft, которые я цитировал, похоже, ссылаются на синтаксис присоединенных событий XAML, а не на реальные присоединенные события. Однако страница MSDN с обзором прикрепленных событий продолжает показывать вам, как реализовать фактическое присоединенное событие, в отличие от обучающего комплекта.
Mouse.MouseDownEvent - пример перенаправленного события, объявленного в статическом классе с соответствующими статическими обработчиками добавления и удаления, иначе называемыми присоединенным событием. Тем не менее, ButtonBase.ClickEvent является обычным перенаправленным событием, хотя его все еще можно использовать с синтаксисом присоединенного события XAML так же, как и с фактическим вложенным событием.
Цель фактического присоединенного события состоит в том, что оно позволяет разработчикам объявлять новые перенаправленные события для существующих классов, производных от UIElement, без необходимости создавать их подклассы; Это означает, что вы можете просто прикрепить новые перенаправленные события, не добавляя их в классы, которые вы хотите вызвать или обработать. Но, подождите минутку... разве это не главная цель чисто перенаправленного события?
Страница обзора перенаправленных событий в MSDN: http://msdn.microsoft.com/en-us/library/ms742806.aspx
Функциональное определение: маршрутизируемое событие - это тип события, которое может вызывать обработчики для нескольких слушателей в дереве элементов, а не только для объекта, вызвавшего событие.
Из этого функционального определения кажется, что любое перенаправленное событие по существу обеспечивает ту же самую точную функциональность, что и прикрепленное событие. Таким образом, в основном присоединенное событие на самом деле является просто средством объявления перенаправленного события в статическом классе и не дает никаких преимуществ по сравнению с обычными перенаправленными событиями.
Дайте мне знать, что вы думаете, потому что я могу что-то здесь упустить.
Спасибо, Тим Валентин
2 ответа
Разница в основном синтаксическая, обе ссылки на делегаты обрабатываются в EventFanager WPF, но то, что дают вам прикрепленные события, - это возможность объявлять универсальную функциональность без необходимости раздувать реализацию всех ваших классов.
В случае обычного перенаправленного события класс предоставляет интерфейс, чтобы в какой-то момент он мог ответить на событие, вызвав обработчик события. Но все, что нужно знать WPF, это то, является ли он объектом производного от заданного типа и зарегистрирован ли обработчик. Это означает, что мы можем создавать более простые иерархии классов, а также поддерживаем принцип Open-Closed (Open to Extension, Closed to Modification). Таким образом, программист может определить новое поведение, которое должно иметь несколько классов, но не нужно изменять исходные классы.
Смотрите также Прикрепленные свойства
Копирование комментария к ответу, чтобы он в итоге не потерялся:
Присоединенное событие — это событие, которое может быть присоединено к любому объекту, а не только к объекту, определяющему событие.
Событие Routed — это событие, которое может быть перенаправлено обработчикам, не являющимся частью объекта.
Событие может быть как перенаправленным, так и прикрепленным событием. Например, является прикрепленным событием, потому что вы можете прикрепить это событие к объектам, отличным от
Button
объект. Это также маршрутизируемое событие, потому что оно может быть обработано несколькимиButton.Click
обработчики событий в дереве пользовательского интерфейса, если вы не остановите это поведение, например, пометив событие как обработанное в одном из обработчиков.
(от Рэйчел