·路由事件与直接事件的区别:直接事件激发时,发送者直接将消息通过事件订阅交送给事件响应者,事件响应者使用其事件处理器方法对事件的发生作出响应、驱动程序逻辑按客户需求运行;路由事件的事件拥有者和事件响应者之间则没有直接显示的订阅关系,事件的拥有者只负责激发事件,事件将由谁响应它并不知道,事件的响应者则安装有事件侦听器,针对某类事件进行侦听,当有此类事件传递至此时,事件响应者就使用事件处理器来响应事件并决定事件是否可以继续传递。
要在哪个控件侦听控件,就调用哪个控件的AddHandler方法把想侦听的事件与事件处理器关联起来。AddHandler方法源自UIElement类,也就是说,所有UI控件都具有这个方法。 路由事件本身是一个RoutedEvent类型的静态成员变量。若想查看事件的源头,就使用e.OriginalSource,使用的时候要使用as/is操作符或强制类型转换把它转换/识别为正确的类型。事例如下:
XAML代码:
<Grid x:Name="gridRoot" Background="Lime">
<Grid x:Name="gridA" Background="Blue" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Canvas x:Name="canvasLeft" Grid.Column="0" Background="Red" Margin="10">
<Button x:Name="buttonLeft" Content="Left" Width="40" Height="100" Margin="10"/>
</Canvas>
<Canvas x:Name="canvasRight" Grid.Column="1" Background="Yellow" Margin="10">
<Button x:Name="buttonRight" Content="Right" Width="40" Height="100" Margin="10"/>
</Canvas>
</Grid>
</Grid>
C#代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.gridRoot.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.ButtonClicked));
}
private void ButtonClicked(object sender, RoutedEventArgs e)
{
MessageBox.Show((e.OriginalSource as FrameworkElement).Name);
}
}
也可以在XAML里添加路由事件处理器:
<Grid x:Name="gridRoot" Background="Lime" Button.Click="ButtonClicked"/>或者
<Grid x:Name="gridRoot" Background="Lime" ButtonBase.Click="ButtonClicked"/>
创建自定义路由事件大体可分为三个步骤:
(1)、声明并注册路由事件;
(2)、为路由事件添加CLR事件包装;
(3)、创建可以激发路由事件的方法。
定义路由事件,声明一个由public static readonly修饰的RoutedEvent类型字段,然后使用EventManager类的RegisterRoutedEvent方法进行注册。
激发路由事件,首先创建需要让事件携带的消息(RoutedEventArgs类的实例)并把它与路由事件关联,然后调用元素的RaiseEvent方法(继承自UIElement类)把事件发送出去。注意:这与激发传统直接事件的方法不同,传统直接事件的激发是通过调用CLR事件的Invoke方法来实现,而路由事件的激发与作为其包装器的CLR事件毫不相干。事例如下:
XAML代码:
<Window x:Class="MyTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MyTest"
Title="WPF Test" WindowStartupLocation="CenterScreen" Height="300" Width="300"
x:Name="window_1" local:TimeButton.ReportTime="ReportTimeHandler">
<Grid x:Name="grid_1" local:TimeButton.ReportTime="ReportTimeHandler">
<Grid x:Name="grid_2" local:TimeButton.ReportTime="ReportTimeHandler">
<Grid x:Name="grid_3" local:TimeButton.ReportTime="ReportTimeHandler">
<StackPanel x:Name="stackPanel_1" local:TimeButton.ReportTime="ReportTimeHandler">
<ListBox x:Name="listBox_1"/>
<local:TimeButton x:Name="timeButton" Width="80" Height="80" Content="报时" local:TimeButton.ReportTime="ReportTimeHandler"/>
</StackPanel>
</Grid>
</Grid>
</Grid>
</Window>
C#代码:
public class ReportTimeEventArgs : RoutedEventArgs
{
public DateTime ClickTime { get; set; }
public ReportTimeEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
{
}
}
public class TimeButton : Button
{
public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble,
typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));
public event RoutedEventHandler ReportTime
{
add { this.AddHandler(ReportTimeEvent, value); }
remove { this.RemoveHandler(ReportTimeEvent, value);}
}
protected override void OnClick()
{
base.OnClick();
ReportTimeEventArgs args = new ReportTimeEventArgs(ReportTimeEvent, this);
args.ClickTime = DateTime.Now;
this.RaiseEvent(args);
}
}
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ReportTimeHandler(object sender, ReportTimeEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
string timeStr = e.ClickTime.ToLongTimeString();
string content = string.Format("{0} 到达 {1}", timeStr, element.Name);
this.listBox_1.Items.Add(content);
}
}
如果想让一个路由事件在某个结点处不再继续传递的方法:路由事件携带的事件参数必须是RoutedEventArgs类或其派生类,将该类型的Handled属性设置为true,路由事件就不再传递。如:
private void ReportTimeHandler(object sender, ReportTimeEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
string timeStr = e.ClickTime.ToLongTimeString();
string content = string.Format("{0} 到达 {1}", timeStr, element.Name);
this.listBox_1.Items.Add(content);
if (element == this.grid_2)
e.Handled = true;
}
本文出自 “墨池小样儿” 博客,请务必保留此出处http://306702895.blog.51cto.com/8366753/1622672
原文地址:http://306702895.blog.51cto.com/8366753/1622672