一、什么是逻辑树
逻辑树就是描述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、点击按钮,界面运行效果