WPF路由事件学习转(二)

在传统的.net中已经有了事件机制了,为什么在WPF中要加入路由事件来取代事件呢,最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,从而有了两个概念,LogicalTree 和 VisualTree,那么它们分别是什么呢,举个例子:


这就是LogicalTree,一个Grid里面镶嵌了其他控件或布局组件,这相当于一棵树中的叶子。而VisualTree呢?它就是一个树中的叶子里面的结构,用放大镜看一下,其实叶子里面的结构也是一颗树结构,这就是VisualTree了,例如

好了,既然WPF中使用这样的一个设计理念,路由事件就是特别为WPF而生的,它的功能就是可以将一个事件从触发点沿着树向上或者向下传播。而需要对这个事件作出反应的地方添加一个监听器,就会有相应的反应了,当然,它的传递是可以用代码来停止的。

下面先说一下WPF内置的路由事件和原理,然后我们来创建一个属于自己的路由事件。

(一)WPF内置的路由事件

这里引用一下《深入浅出WPF》中的一个很简单明了的例子:

Xaml代码如下:

<Window x:Class="WpfApplication1.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="MainWindow" Height="190" Width="246">

<Grid x:Name="GridRoot" Background="Lime">

<Grid x:Name="GridA" Margin="10" Background="Blue">

<Grid.ColumnDefinitions>

<ColumnDefinition></ColumnDefinition>

<ColumnDefinition></ColumnDefinition>

</Grid.ColumnDefinitions>

<Canvas x:Name="CanvasLeft" Grid.Column="0" Background="Red" Margin="10">

<Button x:Name="ButtonLeft" Width="65" Height="100" Margin="10" Content="Left"></Button>

</Canvas>

<Canvas x:Name="CanvasRight" Grid.Column="1" Background="Yellow" Margin="10">

<Button x:Name="ButtonRight" Width="65" Height="100" Margin="10" Content="Right"></Button>

</Canvas>

</Grid>

</Grid>

</Window>

界面如下:

当单击Left按钮的时候,Button.Click事件被触发,并且沿着ButtonLeft→CanvasLeft→GridA→GridRoot→Window这条路线向上传递,当单击Right按钮就会沿着ButtonRight→CanvasRight→GridA→GridRoot→Window这条路线向上传递,这里还没有添加监听器,所以是没有反应的。

如何加入监听器,我们可以再XAML中添加,如这样:

<Grid x:Name="GridA" Margin="10" Background="Blue" Button.Click="Button_Click">

我们在GridA中添加了Button.Click="Button_Click"这个事件处理器,就是监听器,并且事件处理交由Button_Click负责,那么后台的Button_Click函数体是怎样的呢,我们看一下

private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("我到达了:" + (sender as FrameworkElement).Name+"原来是你激发了我:"+(e.Source as FrameworkElement).Name);
}

我们分析一下,那两个参数到底是什么呢?

参数一:sender,这是听者,就是监听的地方,如果点击了Left按钮,那么Left按钮就会大声说:“我被点击了”这个事件向上传递,知道到了设有监听Button.Click事件的地方,这个地方就是sender。

参数二:是RoutEventArgs类型的,这个参数携带了一些重要信息,例如事件是从哪里来的,上一个传到哪里等,都可以利用这个参数来查询。

好了,我们运行一下程序。

注意:路由事件向上传递,这是冒泡的传递方式,是系统默认的,我们还可以设置它为隧道模式或者直接模式,下面自定义路由事件会说到。

(二)自定义路由事件

其实自定义路由事件和自定义依赖项属性十分相似,下来就开始吧

创建自定义路由事件分为3个步骤:

1:声明并注册路由事件。

2:利用CLR事件包装路由事件。

3:创建可以激发路由事件的方法。

好,现在我创建一个能够报告自己在哪个位置里面的路由事件,我们一起去控件里面旅游一下。

先创建继承RoutedEventArgs类的派生类用来携带位置消息

public class ReportLocationEventArgs:RoutedEventArgs

{
public ReportLocationEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { }
public string Location { set; get; }
}

其中的Location属性是用来存放位置的.

然后就到主体了

public class ReportLocation : Button//继承Button  制造相关事件
{
//声明并定义路由事件
public static readonly RoutedEvent ReportLocationEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportLocationEventArgs>), typeof(ReportLocation));
//CLR事件包装器
public event RoutedEventHandler ReportTime
{
add { this.AddHandler(ReportLocationEvent, value); }
remove { this.RemoveHandler(ReportLocationEvent, value); }
}
//重写单击事件,激发路由事件
protected override void OnClick()
{
base.OnClick();
ReportLocationEventArgs Myargs = new ReportLocationEventArgs(ReportLocationEvent, this);
Myargs.Location = this.Name;
this.RaiseEvent(Myargs);

}

}

先声明并定义注册路由事件,我们用EventManager.RegisterRoutedEvent方法来注册的参数有4个。

第一个参数是路由事件的名称Name。

第二个参数是路由事件的传递方式,有三种第一种是Bubble是冒泡模式,这种模式是从触发点向上传递,知道最外层。第二种是Direct就是传统的事件一样的。第三种是隧道模式,这和冒泡的相反,向下传递。

第三个参数是路由事件处理器类型。

第四个参数是拥有这个路由事件的类型。

然后用就是包装路由事件了,语法如上图。

最后激发设定路由事件,这是使用RaiseEvent()方法来触发的。!!!!!

在XAML中,设计如下:

<Window x:Class="WPF路由事件.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF路由事件"
Title="MainWindow" Name="Window" Height="359" Width="255" local:ReportLocation.ReportTime="ReportTimeHandler">
<Grid x:Name="GridRoot" Background="Lime" local:ReportLocation.ReportTime="ReportTimeHandler" >
<Grid x:Name="GridA" Margin="10" Background="Blue" local:ReportLocation.ReportTime="ReportTimeHandler">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas x:Name="CanvasLeft" Grid.Column="0" Background="Red" Margin="10" local:ReportLocation.ReportTime="ReportTimeHandler">
<local:ReportLocation x:Name="ButtonLeft" Width="65" Height="100" Content="Left" local:ReportLocation.ReportTime="ReportTimeHandler"></local:ReportLocation>
</Canvas>
<Canvas x:Name="CanvasRight" Grid.Column="1" Background="Yellow" Margin="10">
<local:ReportLocation x:Name="ButtonRight" Width="65" Height="100" Content="Right" local:ReportLocation.ReportTime="ReportTimeHandler"></local:ReportLocation>
</Canvas>
<ListBox Name="listbox" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="134" Margin="10,165,0,0" VerticalAlignment="Top" Width="207"></ListBox>
</Grid>
</Grid>
</Window>

界面如下:

那么最后看一下事件处理器是怎样的

WPF路由事件学习转(二)

时间: 2024-10-11 13:23:09

WPF路由事件学习转(二)的相关文章

WPF路由事件二:路由事件的三种策略

一.什么是路由事件 路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件.路由事件是一个CLR事件. 路由事件与一般事件的区别在于:路由事件是一种用于元素树的事件,当路由事件触发后,它可以向上或向下遍历可视树和逻辑树,他用一种简单而持久的方式在每个元素上触发,而不需要任何定制的代码(如果用传统的方式实现一个操作,执行整个事件的调用则需要执行代码将事件串联起来). 路由事件的路由策略: 所谓的路由策略就是指:路由事件实现遍历元素的方式. 路由事件一般使用以下三

[总结]使用WPF路由事件过程中遇到的一些小问题

写在前面 本文一开始会给出一个使用WPF路由事件的实例,因为本文所有的表述都将基于该实例.而本文所给实例来自于<WPF自定义路由事件>一文,在<WPF自定义路由事件>一文中会对实例代码做详细说明,所以,大家在阅读本文实例代码期间若存在疑问,可以先去看看<WPF自定义路由事件>一文,看是否能从中获得你想要的解答. 本文实例 1 新建DetailReportEventArgs类,该类派生自RoutedEventArgs类,RoutedEventArgs类包含与路由事件相关的

WPF的Binding学习笔记(二)

原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的皮毛, 然后就做别的事去了, 等回头再来看WPF的时候, 哈忘记了~ 于是写个例子补一下, 在继续学习Binding. 1, 首先准备好一个类 public class Hero { public Hero(int id, string name, string skill, bool hasM)

理解WPF路由事件

(一)什么时路由事件功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件.实现定义:路由事件是一个 CLR 事件,可以由 RoutedEvent 类的实例提供支持并由 Windows Presentation Foundation (WPF) 事件系统来处理(二)路由事件的划分(1)冒泡:针对事件源调用事件处理程序.路由事件随后会路由到后续的父元素,直到到达元素树的根.(2)隧道:最初将在元素树的根处调用事件处理程序.随后,路由事件将朝着路由事件

WPF 路由事件

每每谈到WPF的路由事件,我总是比较模糊的,因为我一般很少用,因为一般是用Binding来满足数据驱动界面的要求,要么就是通过路由命令来执行我想要做的方法,路由事件确实用得少,那么路由事件跟一般的事件的区别在哪里呢?如何使用呢?下面讲揭开其神秘的面纱: 首先说一说事件的历史,在windows操作系统上运行程序,都是消息驱动的,早期Windows API开发和MFC开发的时候可以直接看到各种消息,并且定义消息,到了VB和COM的时代,消息被封装成了事件,到了.NET时代也是事件,但是是直接式的,但

WPF路由事件一:逻辑树和可视树

一.什么是逻辑树 逻辑树就是描述WPF界面元素的实际构成,它是由程序在XAML中所有的UI元素组成.最显著的特点就是由布局控件.或者其他常用的控件组成. 1 <Window x:Class="WpfRouteEvent.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.c

WPF路由事件:逻辑树和可视树

一.什么是逻辑树 逻辑树就是描述WPF界面元素的实际构成,它是由程序在XAML中所有的UI元素组成.最显著的特点就是由布局控件.或者其他常用的控件组成. 1 <Window x:Class="WpfRouteEvent.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.c

WPF自定义路由事件(二)

WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件. 1.WPF内置路由事件 WPF中的大多数事件都是路由事件,WPF有3中路由策略: 具体不多讲,单需要注意的是WPF路由事件是沿着VIsualTree传递的.VisualTree与LogicalTree的区别在于:LogicalTree的叶子节点是构成用户界面的控件(xaml紧密相关),而VisualTree要连控件中的细微结构也

WPF自定义路由事件

一 概要 本文通过实例演示WPF自定义路由事件的使用,进而探讨了路由事件与普通的CLR事件的区别(注:"普通的CLR事件"这个说法可能不太专业,但是,我暂时也找不到什么更好的称呼,就这么着吧,呵呵.)(扩展阅读:例说.NET事件的使用). 二 实例演示与说明 1 新建DetailReportEventArgs类,该类派生自RoutedEventArgs类,RoutedEventArgs类包含与路由事件相关的状态信息和事件数据.DetailReportEventArgs类中定义了属性Ev