29

问题是,经过我所有的研究,我仍然找不到常规路由事件和附加事件之间的区别。功能上有什么区别?还是其他人同意没有?

执行

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 的自定义添加和删除访问器;两者都在 ButtonBase 派生的 UIElement 基类中声明。MouseDownEvent 有两个静态方法 AddMouseDownHandler 和 RemoveMouseDownHandler,它们最终调用 UIElement 中声明的两个 AddHandler 和 RemoveHandler 方法,就像 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 Training Kit for Exam 70-511 - Windows Applications Development with Microsoft .NET Framework 4 指出:

控件可以为控件自身无法引发的事件定义处理程序。这些事件称为附加事件。例如,考虑网格中的 Button 控件。Button 类定义了 Click 事件,但 Grid 类没有。但是,您仍然可以通过在 XAML 代码中附加 Button 控件的 Click 事件来为网格中的按钮定义处理程序。

在整个 Microsoft 学习资源中,“附加事件”一词似乎很模糊,尽管很明显这里有两个不同但密切相关的概念:附加事件和 XAML 附加事件语法。我引用的两个 Microsoft 资源似乎都指的是 XAML 附加事件语法,而不是实际附加事件。但是,附加事件概述 MSDN 页面确实继续向您展示如何实现实际附加事件,而培训工具包没有。

Mouse.MouseDownEvent 是在具有相应静态添加和删除处理程序的静态类上声明的路由事件的示例,也称为附加事件。但是,ButtonBase.ClickEvent 是一个普通的路由事件,尽管它仍然可以以与实际附加事件相同的方式与 XAML 附加事件语法一起使用。

实际附加事件的目的是允许开发人员为现有的 UIElement 派生类声明新的路由事件,而不必对它们进行子类化;这意味着您可以附加新的路由事件,而无需它们实际存在于您要引发或处理它们的类上。但是,等一下……这不是纯路由事件的主要目的吗?

MSDN 上的路由事件概述页面指出:http: //msdn.microsoft.com/en-us/library/ms742806.aspx

功能定义:路由事件是一种事件类型,它可以在元素树中的多个侦听器上调用处理程序,而不仅仅是在引发事件的对象上。

从该功能定义看来,任何路由事件本质上都提供与附加事件相同的功能。因此,基本上附加事件实际上只是在静态类上声明路由事件的一种方式,并且与普通路由事件相比并没有真正提供任何好处。

让我知道你的想法,因为我可能在这里遗漏了一些东西。

谢谢,蒂姆瓦伦丁

4

2 回答 2

5

区别主要在于语法,两个委托引用都由 WPF 的 EventManager 处理,但附加事件给您的是声明通用功能的能力,而无需膨胀所有类的实现。

在普通路由事件的情况下,该类提供了能够在某个时候通过调用事件处理程序来响应事件的接口。但是所有 WPF 需要知道的是它是否是从给定类型派生的对象以及是否注册了处理程序。这意味着我们可以制作更简单的类层次结构,并且还支持开闭原则(对扩展开放,对修改封闭)。这样,程序员可以定义几个类应该具有但不需要修改原始类的新行为。

另请参阅附加属性

于 2014-01-23T21:33:50.220 回答
1

将评论复制到答案中,以免最终丢失:

附加事件是可以附加到任何对象的事件,而不仅仅是定义事件的对象。

Routed 事件是可以路由到不属于对象的处理程序的事件。

一个事件可能既是路由事件又是附加事件。例如,Button.Click是一个附加事件,因为您可以将该事件附加到对象以外的Button对象。它也是一个路由事件,因为它可以由Button.ClickUI 树中的多个事件处理程序处理,除非您停止此行为,例如将事件标记为在其中一个处理程序中处理。

(雷切尔 2012 年 11 月 8 日 20:39)

于 2021-01-11T18:24:32.727 回答