逻辑树与可视化树

介绍

WPF用户界面的元素是层次相关的。这个关系被称作逻辑树。一个元素的模板由多个可视化元素组成,这棵树被称作可视化树。WPF区分这两棵树是因为,有些问题你只需要逻辑树,而其他问题你想要全部的元素。

<Window>
    <Grid>
        <Label Content="Lable" />
        <Button Content="Button" />
    </Grid>
</Window>

为什么我们需要两种不同的树

一个WPF控件由多个更原始的控件组成。一个按钮由边框,矩形和一个内容表示者组成。这些控件是按钮的可视化孩子。
当WPF渲染按钮时,元素本身没有外观,但它遍历可视化树并渲染它的可视化孩子。层次关系还可以用来做命中测试(?)或者布局等等。
但是有些时候你对控件模板的边框和矩形不感兴趣。特别是模板可以被替换,所以你不该关联到这个可视化树的结构。因为你想要仅包含真实的控件的更健壮的树,而不是所有的模板部分。这就是逻辑树的适用性。

逻辑树

逻辑树描述了用户界面的元素之间的关系。逻辑树负责:

  • 继承依赖属性的值
  • 解析动态资源引用
  • 为绑定查找元素名
  • 转发路由事件

可视化树

可视化树包含所有的逻辑元素包含每个元素的模板的可视化元素。可视化树负责:

  • 渲染可视化元素
  • 传播元素不透明度
  • 传播布局和渲染变换(?)
  • 传播IsEnabled属性
  • 击中测试
  • 相对资源(查找祖先)

用程序在可视化树中查找祖先

如果你有用户界面的孩子元素,并且你想要从父元素访问数据,但是你不知道元素在什么层级,最好的解决方案是向上查找直到找到请求类型的元素。

public static class VisualTreeHelperExtensions
{
    public static T FindAncestor<T>(DependencyObject dependcyObject)
        where T : class
    {
        DependencyObject target = dependencyObject;
        do
        {
            target = VisualTreeHelper.GetParent(target);
        }
        while(target != null && !(target is T));
        return target as T;
    }
}

下列例子展示了如何使用这个帮助类。它从this开始向上查找可视化树,直到它找到一个类型为Grid的元素。如果这个帮助类到达了树的根,那么返回空。

var grid = VisualTreeHelperExtensions.FindAncestor<Grid>(this);
posted @ 2023-07-15 14:50  Juston007  阅读(108)  评论(0)    收藏  举报