路由事件
Avalonia中的大多数事件都是作为路由事件实现的。路由事件是在整个树上引发的事件,而不仅仅是引发事件的控件。
什么是路由事件
一个典型的Avalonia应用程序包含许多元素。无论是在代码中创建还是在XAML中声明,这些元素都存在于彼此之间的元素树关系中。事件路由可以根据事件定义的不同方向进行传播,但通常路由从源元素开始,然后通过元素树向上"冒泡",直到达到元素树的根(通常是页面或窗口)。如果您之前使用过HTML DOM,这个冒泡概念可能会很熟悉。
路由事件的顶级场景
以下是激发路由事件概念的场景的简要总结,以及为什么典型的CLR事件对于这些场景来说是不够的:
控件组合和封装: Avalonia中的各种控件具有丰富的内容模型。例如,您可以将图像放在Button
中,这实 际上扩展了按钮的可视树。但是,即使用户点击的像素实际上是图像的一部分,添加的图像也不能破坏导致按钮对其内容的Click
做出响应的命中测试行为。
单一处理程序附加点: 在Windows Forms中,您必须多次附加相同的处理程序来处理可能从多个元素引发的事件。路由事件使您只需附加一次处理程序,就像前面的示例中所示,并使用处理程序逻辑来确定事件的来源(如果需要)。例如,这可能是先前显示的XAML的处理程序:
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
var source = e.Source as Control;
switch (source.Name)
{
case "YesButton":
// 在这里执行某些操作...
break;
case "NoButton":
// 执行某些操作...
break;
case "CancelButton":
// 执行某些操作...
break;
}
e.Handled=true;
}
类处理: 路由事件允许由类定义的静态处理程序。这个类处理程序有机会在任何附加的实例处理程序之前处理事件。
无需反射引用事件: 某些代码和标记技术需要一种方法来标识特定的事件。路由事件创建一个RoutedEvent
字段作为标识符,提供了一种强大的事件标识技术,不需要静态或运行时反射。
路由事件的实现方式
路由事件是由RoutedEvent
类的实例支持并在Avalonia事件系统中注册的CLR事件。通常,从注册中获取的RoutedEvent
实例被保留为注册并因此“拥有”路由事件的类的public
static
readonly
字段成员。与同名的CLR事件(有时称为“包装器”事件)的连接是通过覆盖CLR事件的add
和remove
实现来完成的。通常,add
和remove
被留作隐式默认值,使用适当的语言特定事件语法来添加和移除该事件的处理程序。路由事件的支持和连接机制在概念上类似于Avalonia属性是由AvaloniaProperty
类支持并在Avalonia属性系统中注册的CLR属性。
以下示例显示了自定义Tap
路由事件的声明,包括RoutedEvent
标识符字段的注册和公开以及Tap
CLR事件的add
和remove
实现。
public class SampleControl: Control
{
public static readonly RoutedEvent<RoutedEventArgs> TapEvent =
RoutedEvent.Register<SampleControl, RoutedEventArgs>(nameof(Tap), RoutingStrategies.Bubble);
// Provide CLR accessors for the event
public event EventHandler<RoutedEventArgs> Tap
{
add => AddHandler(TapEvent, value);
remove => RemoveHandler(TapEvent, value);
}
}
路由事件处理程序和XAML
要使用XAML添加事件处理程序,您需要将事件名称声明为元素的属性,该元素是事件的监听器。属性的值是您实现的处理程序方法的名称,该方法必须存在于代码后台文件的类中。
<Button Click="b1SetColor">button</Button>
添加标准CLR事件处理程序的XAML语法与添加路由事件处理程序的语法相同,因为您实际上是将处理程序添加到具有路由事件实现的CLR事件包装器上。