WPF中提供了遍历逻辑树和视觉树的辅助类:System.Windows.LogicalTreeHelper和 System.Windows.Media.VisualTreeHelper。 注意遍历的位置,逻辑树可以在类的构造函数中遍历。但是,视觉树必须在经过至少一次的布局后才能形成。 所以它不能在构造函数遍历。通常是在OnContentRendered进行,这个函数为在布局发生后被调用。 其实每个Tree结点元素本身也包含了遍历的方法。 比如,Visual类包含了三个保护成员方法VisualParent、 VisualChildrenCount、GetVisualChild。通过它们可以访问Visual的父元素和子元素。而对于 FrameworkElement,它通常定义了一个公共的Parent属性表示其逻辑父元素。 特定的FrameworkElement子类用不同的方式暴露了它的逻辑子元素。比如部分子元素是Children Collection,有是有时Content属性,Content属性强制元素只能有一个逻辑子元素。
为了方便理解,直接上代码:
前台XAML代码如下:
<Window x:Class="WpfApp1112.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="300"> <StackPanel> <Label>Hello,world!</Label> </StackPanel> </Window>
后台代码如下:
/// <summary> /// Window2.xaml 的交互逻辑 /// </summary> public partial class Window2 : Window { public Window2() { InitializeComponent(); printLogincalTree(0, this); } protected override void OnContentRendered(EventArgs e) { base.OnContentRendered(e); printVisualTree(0,this); } /// <summary> /// 打印逻辑树 /// </summary> /// <param name="depth"></param> /// <param name="obj"></param> void printLogincalTree(int depth, object obj) { Debug.WriteLine(new string(' ', depth) + obj); //打印空格,方便查看 if (!(obj is DependencyObject)) return; //如果不是DependencyObject,如string等类型 //递归打印逻辑树 foreach (object child in LogicalTreeHelper.GetChildren(obj as DependencyObject)) { printLogincalTree(depth + 1, child); } } /// <summary> /// 打印视觉树 /// </summary> /// <param name="depth"></param> /// <param name="obj"></param> void printVisualTree(int depth, DependencyObject obj) { Debug.WriteLine(new string(' ', depth) + obj); //打印空格,方便查看 //递归打印视觉树 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { printVisualTree(depth + 1, VisualTreeHelper.GetChild(obj, i)); } } }
打印结果如下: