Wpf 简明教程
WPF - Routed Events
routed event 是一种事件类型,可以在元素树中的多个侦听器上调用处理程序,而不仅仅是引发该事件的对象。它基本上是一个由 Routed Event 类的实例支持的 CLR 事件。它在 WPF 事件系统中注册。RoutedEvents 有三种主要的路由策略,如下所示:
-
Direct Event
-
Bubbling Event
-
Tunnel Event
Direct Event
直接事件类似于 Windows 窗体中的事件,它们是由事件发源所在的元素触发的。
与标准 CLR 事件不同,直接路由事件支持类处理,并且可以在自定义控件样式中的事件设置器和事件触发器中使用。
直接事件的一个好例子是 MouseEnter 事件。
Tunnel Event
元素树根上的事件处理程序被调用,然后该事件沿着可视化树向下移动到所有子节点,直到到达事件发源的元素。
冒泡事件和隧道事件之间的区别在于隧道事件总是从预览开始。
在 WPF 应用程序中,事件通常被实现为隧道/冒泡对。因此,你将有一个预览 MouseDown,然后是 MouseDown 事件。
下面给出了 Routed 事件的一个简单示例,其中创建了一个按钮和三个文本块,并具有一些属性和事件。
<Window x:Class = "WPFRoutedEvents.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow" Height = "450" Width = "604" ButtonBase.Click = "Window_Click" >
<Grid>
<StackPanel Margin = "20" ButtonBase.Click = "StackPanel_Click">
<StackPanel Margin = "10">
<TextBlock Name = "txt1" FontSize = "18" Margin = "5" Text = "This is a TextBlock 1" />
<TextBlock Name = "txt2" FontSize = "18" Margin = "5" Text = "This is a TextBlock 2" />
<TextBlock Name = "txt3" FontSize = "18" Margin = "5" Text = "This is a TextBlock 3" />
</StackPanel>
<Button Margin = "10" Content = "Click me" Click = "Button_Click" Width = "80"/>
</StackPanel>
</Grid>
</Window>
这是为 Button、StackPanel 和 Window 实现 Click 事件的 C# 代码。
using System.Windows;
namespace WPFRoutedEvents {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
txt1.Text = "Button is Clicked";
}
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
}
private void Window_Click(object sender, RoutedEventArgs e) {
txt3.Text = "Click event is bubbled to Window";
}
}
}
当你编译并执行以上代码时,它将产生以下窗口:
当你单击按钮时,文本块将更新,如下所示。
如果你想在任何特定级别停止路由事件,那么你需要设置 e.Handled = true;
让我们将 StackPanel_Click 事件更改为如下所示:
private void StackPanel_Click(object sender, RoutedEventArgs e) {
txt2.Text = "Click event is bubbled to Stack Panel";
e.Handled = true;
}
当你单击按钮时,你会观察到单击事件不会传递到窗口,并且会停止在堆栈面板上,并且第 3 个文本块不会更新。
Custom Routed Events
在 .NET 框架中,也可以定义自定义路由事件。你需要按照下面给出的步骤在 C# 中定义一个自定义路由事件。
-
使用系统调用 RegisterRoutedEvent 声明并注册您的路由事件。
-
指定路由策略,即冒泡、隧道或直接。
-
Provide the event handler.
让我们通过一个示例更深入地了解自定义路由事件。按照以下步骤操作:
-
使用 WPFCustomRoutedEvent 创建一个新的 WPF 项目
-
右键单击您的解决方案,然后选择“添加”>“新项…”
-
将打开以下对话框,现在选择 Custom Control (WPF) 并将其命名为 MyCustomControl 。
-
单击 Add 按钮后,您会看到有两个新文件(Themes/Generic.xaml 和 MyCustomControl.cs)添加到您的解决方案中。
以下 XAML 代码在 Generic.xaml 文件中设置自定义控件的样式。
<ResourceDictionary
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent">
<Style TargetType = "{x:Type local:MyCustomControl}">
<Setter Property = "Margin" Value = "50"/>
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "{x:Type local:MyCustomControl}">
<Border Background = "{TemplateBinding Background}"
BorderBrush = "{TemplateBinding BorderBrush}"
BorderThickness = "{TemplateBinding BorderThickness}">
<Button x:Name = "PART_Button" Content = "Click Me" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
以下是 MyCustomControl class 的 C# 代码,它继承自 Control class ,其中为自定义控件创建了一个自定义路由事件 Click。
using System.Windows;
using System.Windows.Controls;
namespace WPFCustomRoutedEvent {
public class MyCustomControl : Control {
static MyCustomControl() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl),
new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
//demo purpose only, check for previous instances and remove the handler first
var button = GetTemplateChild("PART_Button") as Button;
if (button ! = null)
button.Click + = Button_Click;
}
void Button_Click(object sender, RoutedEventArgs e) {
RaiseClickEvent();
}
public static readonly RoutedEvent ClickEvent =
EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(MyCustomControl));
public event RoutedEventHandler Click {
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
protected virtual void RaiseClickEvent() {
RoutedEventArgs args = new RoutedEventArgs(MyCustomControl.ClickEvent);
RaiseEvent(args);
}
}
}
以下是 C# 中的自定义路由事件实现,当用户单击该事件时,将会显示一个消息框。
using System.Windows;
namespace WPFCustomRoutedEvent {
// <summary>
// Interaction logic for MainWindow.xaml
// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void MyCustomControl_Click(object sender, RoutedEventArgs e) {
MessageBox.Show("It is the custom routed event of your custom control");
}
}
}
以下是 MainWindow.xaml 中的实现,以添加具有路由事件 Click 的自定义控件。
<Window x:Class = "WPFCustomRoutedEvent.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "clr-namespace:WPFCustomRoutedEvent"
Title = "MainWindow" Height = "350" Width = "604">
<Grid>
<local:MyCustomControl Click = "MyCustomControl_Click" />
</Grid>
</Window>
当编译并执行上述代码时,它将生成以下包含自定义控件的窗口。
当您单击自定义控件时,它将生成以下消息。