WPF中文网

LogicalTree逻辑树

WPF使用了若干树结构形式来定义程序元素之间的关系,比如逻辑树和可视化树。要介绍逻辑树和可视化树,我们要先了解两个基类,它们分别是FrameworkElement类和Visual类,FrameworkElement类主要实现控件的布局、逻辑树、支持数据绑定和动态资源引用、控件的样式定义和动画,而Visual类更关注控件的命中测试、坐标转换和边界框计算,即控件呈现更基础的服务支持。所以,FrameworkElement类与WPF的控件“更靠近一些”,比如设置控件的宽度、高度、透明度、显示或隐藏控件,像这些由控件组成的XAML代码就是一棵逻辑树。

那么,逻辑树有什么用途呢?

官方解释

借助逻辑树,内容模型可以方便地循环访问其可能的子对象,从而实现扩展。 此外,逻辑树还为某些通知提供框架,例如在加载逻辑树中的所有对象时。 基本上,逻辑树是框架级别的近似运行时对象图(排除了视觉对象),但其足以用于对你自己的运行时应用程序组合执行多种查询操作。
此外,静态和动态资源引用具有相同的解析过程:针对最初发出请求的对象,沿逻辑树向上查找 Resources 集合,然后沿逻辑树继续向上,检查每一个 FrameworkElement 或 FrameworkContentElement,以查找另一个包含 ResourceDictionary(可能包含该键)的 Resources 值。

有时候,我们需要在后端代码中查找前端XAML某个控件,以便对控件进行某个操作,那么,就可以借助逻辑树来遍历元素。LogicalTreeHelper 类就是专门来遍历查找WPF的逻辑树的。LogicalTreeHelper 类提供用于逻辑树遍历的 GetChildren、GetParent 和 FindLogicalNode 方法。

下面,我们一个例子来说明LogicalTreeHelper 类的使用过程。

前端代码

<Window x:Class="HelloWorld.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:HelloWorld" 
        xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        mc:Ignorable="d" FontSize="14"
        Title="WPF中文网 - 模板 - www.wpfsoft.com" Height="350" Width="500">    
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Border Grid.Column="0" x:Name="_LeftBorder" Width="188" Background="LightCyan">
            <Button Content="当前逻辑树" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Border>
        <Border Grid.Column="1" x:Name="_RightBorder" >
            <TreeView x:Name="_TreeView" Margin="5"/>
        </Border>
    </Grid>
    
</Window>

在上面的前端代码中,根节点是window,在window里面有一个grid控件,在grid控件中有两个ColumnDefinition对象和两个Border 对象,在两个Border 对象中,分别有一个button对象 和TreeView对象。

接下来,我们通过LogicalTreeHelper 类来遍历Window窗体的XAML代码形成的逻辑树,看看结果如何。

后端代码

/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = new MainViewModel();           

    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        TreeViewItem item = new TreeViewItem() { Header = "逻辑树根" };

        LogicalTree(item, this);

        _TreeView.Items.Add(item);
    }

    private void LogicalTree(TreeViewItem item, object element)
    {
        if (!(element is DependencyObject)) return;

        TreeViewItem treeViewItem = new TreeViewItem { Header = element.GetType().Name };

        item.Items.Add(treeViewItem);

        var elements = LogicalTreeHelper.GetChildren(element as DependencyObject);

        foreach (object child in elements)
        {
            LogicalTree(treeViewItem, child);
        }
            
    }
}

在后端代码中,我们利用LogicalTreeHelper.GetChildren方法一层一层地获取child对象,通过递归函数将这个树加载到TreeView当中。

最后,MainWindow的逻辑树就被我们全部显示出来,它与XAML代码保持一致,罗列了前端代码中控件形成的树的样式。

实际上,每个控件因为有Template模板——即每个控件内部也有其构成的元素,换句话说,单看每个控件的组成,其实也是一棵树,只不过,逻辑树并没有将它们显示出来。如果想要在树上不单看到控件组成的树结构,还要看到控件的内部组成结构,那就得用可视化树(VisualTree)。

下一节,我们来介绍VisualTree。

当前课程源码下载:(注明:本站所有源代码请按标题搜索)

文件名:061-《LogicalTree逻辑树》-源代码
链接:https://pan.baidu.com/s/1yu-q4tUtl0poLVgmcMfgBA
提取码:wpff

——重庆教主 2023年9月21日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1