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

Posted zjone391

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="350" Width="525">
 5     <Grid>
 6         <StackPanel>
 7             <TextBox></TextBox>
 8         </StackPanel>
 9     </Grid>
10 </Window>
复制代码

从上面的代码中可以看出,Window、Grid、StackPanel、TextBox其实就是XAML界面的逻辑树。

二、什么是可视树

可视树是由界面上可见的元素构成的,这些元素主要是由从Visual或者Visual3D类中派生出来的类。

上面代码中的Window、Grid、StackPanel、TextBox它们本身就包含一些由Visual或者Visual3D类派生出的一些可视树的元素来组成的。

三、逻辑树和可视树的遍历

逻辑树遍历使用LogicalTreeHelper类。
可视树遍历使用VisualTreeHelper类。

演示遍历逻辑树和可视树

1、XAML界面左边显示逻辑树,右边显示可视树,代码如下:

复制代码
 1 <Window x:Class="WpfRouteEvent.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="350" Width="525">
 5     <Grid>
 6         <DockPanel>
 7             <Button DockPanel.Dock="Top" Click="Button_Click" Content="获取逻辑树和可视树"></Button>
 8             <Grid>
 9                 <Grid.ColumnDefinitions>
10                     <ColumnDefinition></ColumnDefinition>
11                     <ColumnDefinition></ColumnDefinition>
12                 </Grid.ColumnDefinitions>
13                 <DockPanel Grid.Column="0">
14                     <TextBlock DockPanel.Dock="Top" Text="逻辑树"></TextBlock>
15                     <TreeView Name="tvLogicTree"></TreeView>
16                 </DockPanel>
17                 <DockPanel Grid.Column="1">
18                     <TextBlock DockPanel.Dock="Top" Text="可视树"></TextBlock>
19                     <TreeView Name="tvVisualTree"></TreeView>
20                 </DockPanel>
21             </Grid>
22         </DockPanel>
23         
24     </Grid>
25 </Window>
复制代码

2、添加类,用于遍历整个XAML界面的逻辑树和可视树

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Windows;
 7 using System.Windows.Controls;
 8 using System.Windows.Media;
 9 
10 namespace WpfRouteEvent
11 {
12     public class WpfTreeHelper
13     {
14         static string GetTypeDescription(object obj)
15         {
16             return obj.GetType().FullName;
17         }
18 
19         /// <summary>
20         /// 获取逻辑树
21         /// </summary>
22         /// <param name="obj"></param>
23         /// <returns></returns>
24         public static TreeViewItem GetLogicTree(DependencyObject obj)
25         {
26             if (obj == null)
27             {
28                 return null;
29             }
30             //创建逻辑树的节点
31             TreeViewItem treeItem = new TreeViewItem {Header=GetTypeDescription(obj),IsExpanded=true };
32 
33             //循环遍历,获取逻辑树的所有子节点
34             foreach (var child in LogicalTreeHelper.GetChildren(obj))
35             {
36                 //递归调用
37                 var item = GetLogicTree(child as DependencyObject);
38                 if (item != null)
39                 {
40                     treeItem.Items.Add(item);
41                 }
42             }
43 
44             return treeItem;
45         }
46 
47         /// <summary>
48         /// 获取可视树
49         /// </summary>
50         /// <param name="obj"></param>
51         /// <returns></returns>
52         public static TreeViewItem GetVisualTree(DependencyObject obj)
53         {
54             if (obj == null)
55             {
56                 return null;
57             }
58 
59             TreeViewItem treeItem = new TreeViewItem { Header=GetTypeDescription(obj),IsExpanded=true};
60 
61             for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
62             {
63                 var child = VisualTreeHelper.GetChild(obj, i);
64                 var item = GetVisualTree(child);
65                 if (item != null)
66                 {
67                     treeItem.Items.Add(item);
68                 }
69             }
70 
71             return treeItem;
72         }
73     }
74 }
复制代码

3、在按钮的点击事件中将获取的逻辑树和可视树添加到XAML界面中

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Windows;
 7 using System.Windows.Controls;
 8 using System.Windows.Data;
 9 using System.Windows.Documents;
10 using System.Windows.Input;
11 using System.Windows.Media;
12 using System.Windows.Media.Imaging;
13 using System.Windows.Navigation;
14 using System.Windows.Shapes;
15 
16 namespace WpfRouteEvent
17 {
18     /// <summary>
19     /// MainWindow.xaml 的交互逻辑
20     /// </summary>
21     public partial class MainWindow : Window
22     {
23         public MainWindow()
24         {
25             InitializeComponent();
26         }
27 
28         private void Button_Click(object sender, RoutedEventArgs e)
29         {
30             this.tvLogicTree.Items.Add(WpfTreeHelper.GetLogicTree(this));
31             this.tvVisualTree.Items.Add(WpfTreeHelper.GetVisualTree(this));
32         }
33     }
34 }
复制代码

4、点击按钮,界面运行效果

 

以上是关于WPF路由事件:逻辑树和可视树的主要内容,如果未能解决你的问题,请参考以下文章

2022-04-13 WPF面试题 WPF中可视化树和逻辑树的区别是什么?

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

WPF-10 逻辑树和可视化树

路由事件

WPF自学入门WPF路由事件之内置路由事件

1