无废话WPF系列13:路由事件

简介:

逻辑树

<Window>
  <Grid>
    <Button>
      <StackPanel>
        <Image/>
        <TextBlock/>
      </StackPanel>
    </Button>
  </Grid>
</Window>

但是实际上这些元素在运行时会扩展为可是树

image
 

事件路由

对逻辑树和可视树有所了解很有必要,因为路由事件主要是根据可视树进行路由。路由事件支持三种路由策略:气泡、隧道和直接。

气泡事件最为常见,它表示事件从源元素扩散(传播)到可视树,直到它被处理或到达根元素。这样您就可以针对源元素的上方层级对象处理事件。例如,您可向嵌入的 Grid 元素附加一个 Button.Click 处理程序,而不是直接将其附加到按钮本身。气泡事件有指示其操作的名称(例如,MouseDown)。

隧道事件采用另一种方式,从根元素开始,向下遍历元素树,直到被处理或到达事件的源元素。这样上游元素就可以在事件到达源元素之前先行截取并进行处理。根据命名惯例,隧道事件带有前缀 Preview(例如 PreviewMouseDown)。

直接事件类似 .NET Framework 中的正常事件。该事件唯一可能的处理程序是与其挂接的委托。

通常,如果为特殊事件定义了隧道事件,就会有相应的气泡事件。在这种情况下,隧道事件先触发,从根元素开始,下行至源元素,查找处理程序。一旦它被处理或到达源元素,即会触发气泡事件,从源元素上行,查找处理程序。气泡或隧道事件不会仅因调用事件处理程序而停止路由。如果您想中止隧道或气泡进程,可使用您传递的事件参数在事件处理程序中将事件标记为已处理。

示例(我们在Grid上加了一个Button.Click的附加事件:

1
2
3
4
5
6
7
8
9
10
< Window  x:Class="DeepXAML.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:DeepXAML"      
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Title="MainWindow" Height="250" Width="450">
     < Grid  x:Name="rootGrid" Button.Click="rootGrid_Click">
         < Button  x:Name="btnOK" Margin="30">OK</ Button >
     </ Grid >
</ Window >

 

后台代码:

1
2
3
4
5
private void rootGrid_Click(object sender, RoutedEventArgs e)
{
     MessageBox.Show((e.Source as FrameworkElement).Name); //btnOk
     MessageBox.Show((e.OriginalSource as FrameworkElement).Name); //btnOk
}

 

source是指LogicTree的源途,orginalSource指的是VisualTree上的源

 

自定义路由事件示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
< Window  x:Class="DeepXAML.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:DeepXAML"      
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
         Title="MainWindow" Height="250" Width="450">
     < Grid  x:Name="rootGrid" >
         < StackPanel  x:Name="stp1" local:TestButton.ClickTimeEvent="TimeHanler">
             < StackPanel  x:Name="stp2" local:TestButton.ClickTimeEvent="TimeHanler">
                 < StackPanel  x:Name="stp3" local:TestButton.ClickTimeEvent="TimeHanler">
                     < ListBox  x:Name="listBox"></ ListBox >
                     < local:TestButton  local:TestButton.ClickTimeEvent="TimeHanler" Height="50" Margin="30">OK</ local:TestButton >
                 </ StackPanel >
             </ StackPanel >
         </ StackPanel >      
     </ Grid >
</ Window >
1
后台代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using  System;
using  System.Collections.Generic;
using  System.Windows;
using  System.Windows.Data;
using  System.Windows.Documents;
using  System.Windows.Controls;
 
namespace  DeepXAML
{
     public  partial  class  MainWindow : Window
     {
         public  MainWindow()
         {
             InitializeComponent();
     
         }
 
         private  void  TimeHanler( object  sender, TimeEventArgs e)
         {
             FrameworkElement element = sender as  FrameworkElement;
             string  strTime = e.ClickTime.ToLongTimeString();
             this .listBox.Items.Add( element.Name+ ":" + strTime);
         }             
     }
 
     public  class  TimeEventArgs : RoutedEventArgs
     {
         public  TimeEventArgs(RoutedEvent routedEvent, object  source): base (routedEvent,source)
         {          
         }
         public  DateTime ClickTime { get ; set ; }
     }
 
     public  class  TestButton : Button
     {
       public  static  RoutedEvent timeEvent=
           EventManager.RegisterRoutedEvent( "ClickTimeEvent" , RoutingStrategy.Bubble, typeof (EventHandler<TimeEventArgs>), typeof (TestButton));
 
         public  event   RoutedEventHandler ClickTimeEvent
         {
           add { this .AddHandler(timeEvent,value);}
           remove{ this .RemoveHandler(timeEvent,value);}
         }
 
         protected  override  void   OnClick()
         {
               base .OnClick();
             TimeEventArgs args= new  TimeEventArgs(timeEvent, this );
             args.ClickTime=DateTime.UtcNow;
             this .RaiseEvent(args);
         }
     }   
}
本文转自敏捷的水博客园博客,原文链接http://www.cnblogs.com/cnblogsfans/archive/2011/02/27/1966166.html如需转载请自行联系原作者

王德水
相关文章
|
3月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
93 0
|
前端开发 C# Windows
WPF鼠标、键盘、拖拽事件、用行为封装事件
本文主要介绍了WPF中常用的鼠标事件、键盘事件以及注意事项,同时使用一个案例讲解了拓展事件。除此之外,本文还讲述如何用行为(Behavior)来封装事件。
如何解决WPF中 ScrollViewer 内包含 TreeView 或者 ListBox 等控件时滚轮事件被劫持的问题
如何解决WPF中 ScrollViewer 内包含 TreeView 或者 ListBox 等控件时滚轮事件被劫持的问题
|
Java C# 程序员
WPF程序中的弱事件模式
原文:WPF程序中的弱事件模式 在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源。但是,GC有的时并不是按照我们所期望的方式工作。 例如,我想实现一个在窗口的标题栏中实时显示当前的时间,一个比较常规的做法如下:     var...
1141 0
|
C#
WPF 事件触发命令
原文:WPF 事件触发命令 方法一使用mvvmlight: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.
1588 0
|
前端开发 C#
从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?
原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...
1503 0
|
C# 开发框架
Prism for WPF再探(基于Prism事件的模块间通信)
原文:Prism for WPF再探(基于Prism事件的模块间通信) 上篇博文链接 Prism for WPF初探(构建简单的模块化开发框架) 一、简单介绍:   在上一篇博文中初步搭建了Prism框架的各个模块,但那只是搭建了一个空壳,里面的内容基本是空的,在这一篇我将实现各个模块间的通信,在上一篇博文的基础上改的。
1579 0
|
.NET C# Windows
WPF 自定义路由事件
原文:WPF 自定义路由事件 WPF中的路由事件 as U know,和以前Windows消息事件区别不再多讲,这篇博文中,将首先回顾下WPF内置的路由事件的用法,然后在此基础上自定义一个路由事件。 1.WPF内置路由事件   WPF中的大多数事件都是路由事件,WPF有3中路由策略: 具体不多讲,单需要注意的是WPF路由事件是沿着VIsualTree传递的。
1148 0
|
C# 前端开发 监控
WPF事件(一)内置路由事件
原文:WPF事件(一)内置路由事件 Windows是消息驱动的操作系统,运行其上的程序也遵照这个机制运行,随着面向对象开发平台日趋成熟,微软把消息机制封装成了更容易让人理解的事件模型,一个事件包含3个关键点:事...
902 0
|
C#
WPF 为资源字典 添加事件响应的后台类
原文:WPF 为资源字典 添加事件响应的后台类 前言,有许多同学在写WPF程序时在资源字典里加入了其它控件,但又想写事件来控制这个控件,但是资源字典没有CS文件,不像窗体XAML还有一个后台的CS文件,怎么办呢? 在工作时也遇到了这个问题,现在把它分享出来 比如说我们现在要写一个TabControl控件,在TabItem中有一个关闭按钮或其它按钮,这个按钮要能响应某个事件。
1651 0