1.Visual Tree和Logical Tree
Logical Tree:逻辑树,WPF中用户界面有一个对象树构建而成,这棵树叫做逻辑树,元素的声明分层结构形成了所谓的逻辑树!!
Visual Tree:可视树(也叫视觉树),可视树是对逻辑树的扩展,可视树将逻辑树的节点打散,分放到核心棵树组件中,它表述了一些详细的可视化实现,而不是把每个元素当做一个”黑盒“。
我们以一个简单的程序来观察下逻辑树与可视树:

<Window x:Class="WpfApplication28.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" HorizontalAlignment="Center" VerticalAlignment="Center"></Button>
</Grid>
</Window>

窗口中只有一个Button,如何查看这个程序的逻辑树和可视树呢?我们可以轻松用一个工具查看到:
WPF中查看视觉树和逻辑树的工具: WPF Inspector:下载地址:http://wpfinspector.codeplex.com/
安装完成后直接双击打开WPF Inspector:

软件提示目前没有任何正在运行的WPF应用程序。现在我们启动刚才的wpf程序:

发现了名为mainWindow的应用程序,点击Attach:

左侧为可视树,右侧为逻辑树
可以看出:LogicalTree的叶子节点是构成用户界面的控件,逻辑树的结构即为Xaml中控件元素的声明层次结构,最顶级的为Application,最内层为我们创建的Button按钮。

而可视树则包含了更多直接通过Xaml看不到内容,控件中的细微结构也算上了,以Button为例,通过观察可知在Button的内部包含ButtonChrome,用于为Button创建特定于主题的外观。ButtonChrome内包含用于存放单个子控件的ContentPressenter,而Contentpressenter存放了一个TextBlock用于显示Button上的文字信息。
此外,WPF Inspector还可以查看WPF应用程序内的属性、数据绑定、资源、样式、触发器等信息。如图:

利用工具对可视树的查看可以加深对控件内部构造的理解。

2.路由事件
路由事件:一种可以在元素树中向上或向下传播,并沿着传播路径被事件处理程序处理。路由事件主要根据可视树进行路由,路由事件支持三种路由策略:冒泡、隧道、直接,因其沿着可视树进行传播,所以其与Winform中的不同在于,事件的发送者与事件的响应者不一定有直接关系。

2.1.冒泡(Bubble)路由事件:沿着可视树向上传递的路由事件

如果在MainWindow的Grid中添加一个Border,Border中添加一个TextBlock,分别为这些控件注册MouseLeftButtonDown事件,点击TextBlock:

<Window x:Class="WpfApplication32.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="Grid1" Background="CornflowerBlue" MouseLeftButtonDown="OnMouseLeftButtonDown">
<Border x:Name="Border1" Height="100" Width="200" Background="BurlyWood" MouseLeftButtonDown="OnMouseLeftButtonDown">
<TextBlock x:Name="TexlBlock1" Text="TextBlock" Background="Chartreuse" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" MouseLeftButtonDown="OnMouseLeftButtonDown"/>
</Border>
</Grid>
</Window>

后台代码:

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var fra = sender as FrameworkElement;
MessageBox.Show(fra.Name);
}
}

首先被触发的是TextBlock的MouseLeftButtonDown事件,然后是Border,最后是Grid。
如果某个控件不支持所要路由的事件,可以用附加事件来完成,例如StackPanel不包含Click事件,则可以添加如下代码:

<StackPanel Button.Click="ButtonBase_OnClick">
<Button Content="Button1"></Button>
<Button Content="Button2"></Button>
<Button Content="Button3"></Button>
<Button Content="Button4"></Button>
<CheckBox Content="Button5"></CheckBox>
</StackPanel>
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var btn = e.Source as Button;
if (btn == null) return;
MessageBox.Show(btn.Content.ToString());
}

当点击StackPanel中任意Button,该事件均可向上传递到StackPanel中,这样就不必为StackPanel中所有的Button都注册一个点击事件了。

2.2.隧道(Tunnel)路由事件:沿着可视树向下传递的路由事件

隧道事件均以Preview开头

<StackPanel PreviewMouseLeftButtonDown="UIElement_OnPreviewMouseLeftButtonDown">
<Button Content="Button1"></Button>
<Button Content="Button2"></Button>
<Button Content="Button3"></Button>
<Button Content="Button4"></Button>
<CheckBox Content="Button5"></CheckBox>
</StackPanel>

在任意Button处按下鼠标左键:
sender:StackPanel
e.Source:Button
e.OriginalSource:TextBlock

注:

一般情况下,WPF提供的输入事件都是以隧道/冒泡对实现的,隧道事件总是在冒泡事件之前被触发;

如果想中断路由事件,只需在中断处添加e.Handled = true;

如果隧道事件被标记为已处理,则冒泡事件将不会再发生;(两种路由事件的RoutedEventArges是同一个)。

2.3.直接(Direct)路由事件:只有事件源才有机会响应的路由事件

事件仅在源元素上触发的路由事件,类似于普通事件的处理方式。不同之处在于因其仍然是一个路由事件,对WPF提供了更好的支持,事件仍然会参与一些路由事件的特定机制,如事件触发器、类处理机制等。

WPF中的Visual Tree和Logical Tree与路由事件的更多相关文章

  1. WPF 中的逻辑树(Logical Tree)与可视化元素树(Visual Tree)

    一.前言 ​ WPF 中有两种"树":逻辑树(Logical Tree)和可视化元素树(Visual Tree). Logical Tree 最显著的特点就是它完全由布局组件和控件 ...

  2. WPF中在MVVM模式下,后台绑定ListCollectionView事件触发问题

    问题:WPF中MVVM模式下 ListView绑定ListCollectionView时,CurrentChanged无法触发 解决方案: 初期方案:利用ListView的SelectionChang ...

  3. WPF基础学习笔记整理 (六) RoutedEvent路由事件

    基础知识: 传统的事件模型中,会在消息触发时将消息通过事件传给事件的订阅者(显式的事件订阅),事件订阅者使用事件处理程序来做出响应.事件订阅者必须能够直接访问到事件的宿主(拥有者). 路由事件的事件的 ...

  4. WPF 之路由事件和附加事件(六)

    一.消息驱动与直接事件模型 ​ 事件的前身是消息(Message).Windows 是消息驱动的系统,运行其上的程序也遵循这个原则.消息的本质就是一条数据,这条消息里面包含着消息的类别,必要的时候还记 ...

  5. WPF中Logical Tree和Visual Tree的区别

    The Logical TreeThe logical tree describes the relations between elements of the user interface. The ...

  6. 正确理解WPF中的TemplatedParent

    (注:Logical Tree中文称为逻辑树,Visual Tree中文称为可视化树或者视觉树,由于名称不是很统一,文中统一用英文名称代表两个概念,况且VisualTreeHelper和Logical ...

  7. 正确理解WPF中的TemplatedParent (转贴)

    http://blog.csdn.net/idebian/article/details/8761388 (注:Logical Tree中文称为逻辑树,Visual Tree中文称为可视化树或者视觉树 ...

  8. 理解WPF中的视觉树和逻辑树

    轉載地址:http://blog.csdn.net/changtianshuiyue/article/details/26981797 理解WPF中的视觉树和逻辑树  Understanding th ...

  9. wpf中的触发器详解

    原文 http://zwkufo.blog.163.com/blog/static/25882512009724113250883/ 7.1.2 简单逻辑的表示--触发器(1) 在本章的多处介绍中都会 ...

随机推荐

  1. Lib作为“静态库”与“动态库”中的区别

    Lib作为“静态库”与“动态库”中的区别 0. 前言: 什么是静态连接库: 静态库在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中.因此对应的链接方式称为静态链接. 为什么 ...

  2. DOS和批处理基本命令

    http://www.cnblogs.com/leizhao/archive/2013/03/07/2949026.html 1.rem和:: rem注释命令,该命令后的内容不被执行,但能回显 ::注 ...

  3. list列表常用操作

    1.创建列表.只要把逗号分隔的不同的数据项使用方括号括起来即可 List = ['wade','james','bosh','haslem'] 2.使用 range() 创建数字列表 numbers ...

  4. UniGUI的TUniLoginForm窗口自定义背景色和背景图片

    雨田家园 UniGUI的TUniLoginForm窗口自定义背景色 uniGUI的TUniLoginForm类创建的登录窗口默认是不带颜色,可以自定义css风格来改变背景颜色. 一般是通过在UniSe ...

  5. python 数据类型一 (重点是字符串的各种操作)

    一.python基本数据类型 1,int,整数,主要用来进行数学运算 2,bool,布尔类型,判断真假,True,False 3,str,字符串,可以保存少量数据并进行相应的操作(未来使用频率最高的一 ...

  6. spring cloud学习(二) 调用服务

    spring-cloud调用服务有两种方式,一种是Ribbon+RestTemplate, 另外一种是Feign. Ribbon是一个基于HTTP和TCP客户端的负载均衡器,其实feign也使用了ri ...

  7. 详述MSSQL服务在渗透测试中的利用 (下篇)

    part3 MSSQL写文件 步骤1 sp_makewebtask写文件 因为是`SA`权限,如果目标服务器是web服务器,我们也不用去备份了,可以直接写个一句话木马进去到web目录. 在不知道web ...

  8. Swift5 语言指南(二十五) 自动引用计数(ARC)

    Swift使用自动引用计数(ARC)来跟踪和管理应用程序的内存使用情况.在大多数情况下,这意味着内存管理在Swift中“正常工作”,您不需要自己考虑内存管理.当不再需要这些实例时,ARC会自动释放类实 ...

  9. css 的 conic-gradient 学习

    偶然间在微信公众号奇舞周刊上看到了这篇文章<CSS Painting API>,算是对 conic-gradient的初次见面. 后来有空的时候,百度搜了一下,看了这篇文章<CSS神 ...

  10. django基础之二

    一.什么是架构? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有的We ...