WPF中的可视化树(VisualTree)和逻辑树(LogicalTree)

可视化树和逻辑树

我们先来理解一下什么是可视化树和逻辑树。

可视化树:包含最初指定的大多数元素(在XAML或.cs中)以及控件模板中的元素。

通俗点来讲,就是整个元素的构成树,从最上面的结点到最后一个结点(包括控件模板)。

逻辑树:是可视化树的一个子集,它省略了控件模板中的元素。

通俗点来讲,就是不包含控件模板的可视化树

以上的解释仅仅用于简单理解这两个概念以及区别,完整的解释请参考文末的链接,MSDN上的文档将会更准确。

下面我们创建一个Window来演示,XAML如下:

1 <Window>
3         <Grid Name="grid" Grid.Column="1">
4             <Button HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,80,0" Grid.Row="1" Content="获取可视化树" Click="GetVisualTree_Click"></Button>
5             <Button HorizontalAlignment="Right" VerticalAlignment="Center" Content="获取逻辑树" Grid.Row="1" Click="GetLogicalTree_Click"></Button>
6         </Grid>
7 </Window>

在WPF中提供了VisualTreeHelper 和 LogicalTreeHelper 两个类来对可视化树和逻辑树进行操作。

使用VisualTreeHelper来获取Grid的可视化树

 1  public void PrintVisualTree(DependencyObject parent, int level)2  {3      string typeName = parent.GetType().FullName ?? parent.GetType().Name;4      string name = (string)(parent.GetValue(FrameworkElement.NameProperty) ?? "");5      AppendText("           ".Substring(0, level * 2));6      AppendText($"{typeName}:",true);7      AppendText($" {name}");8      AppendText(Environment.NewLine);9      for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i)
10      {
11          DependencyObject child = VisualTreeHelper.GetChild(parent, i);
12          PrintVisualTree(child, level + 1);
13      }
14  }

输出结果如下:

可以看到Grid的视觉树不仅打印了两个Button,还打印了Button的控件模板。

Button控件的控件模板如下:

1 <Border TextBlock.Foreground="{TemplateBinding Foreground}"
2                 x:Name="Border"
3                 CornerRadius="2"
4                 BorderThickness="1">
5                   <ContentPresenter Margin="2"
6                             HorizontalAlignment="Center"
7                             VerticalAlignment="Center"
8                             RecognizesAccessKey="True" />
9 </Border>

使用LogicalTreeHelper来获取Grid的逻辑树

 1 public void PrintLogicalTree(object parent, int level)2 {3     var parentObj = parent as DependencyObject;4     var typeName = parent.GetType().FullName;5     var name = "";6     if (parentObj != null)7     {8         name = (string)(parentObj.GetValue(FrameworkElement.NameProperty) ?? "");9     }
10     else
11     {
12         name = parent.ToString();
13     }
14 
15     AppendText(GetIndentString().Substring(0, level * 2));
16     AppendText($"{typeName}:", true);
17     AppendText($" {name}");
18     AppendText(Environment.NewLine);
19 
20     if (parentObj == null)
21         return;
22 
23     var children = LogicalTreeHelper.GetChildren(parentObj);
24     foreach (object child in children)
25     {
26         PrintLogicalTree(child, level + 1);
27     }
28 }

运行结果如下:

可以看到Grid的逻辑树只显示到了Button的内容这一层。

可视化树的用途

在上面的Button模板中,我们定义了一个Border,并命名为Border,

如果我们想查找这个控件,并为之添加事件处理程序或设置一些属性,都可以通过可视化树来实现。 

首先我们定义一个遍历可视化树的方法

 1  public Visual EnumVisual(Visual myVisual,string controlName)2  {3      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)4      {5          6          Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);7          var nameObj = childVisual.GetValue(NameProperty);8 9          if (nameObj != null && nameObj.ToString() == controlName)
10              return childVisual;
11 
12          EnumVisual(childVisual,controlName);
13      }
14 
15      return null;
16  }

然后我们查找Border,并设置它的CornerRadius属性

 1 //查找控件模板中的名称为Border的控件2 var border = EnumVisual(this.btn1, "Border");3 if (border != null)4 {5     var borderObj = border as Border;6 7     if (borderObj != null)8     {9         borderObj.CornerRadius = new CornerRadius(10);
10     }
11 }

运行效果

实际上我们还可以通过FrameworkTemplate.FindName方法进行查找,使用方法如下:

1 object findObj = this.btn1.Template.FindName("Border",this.btn1);

FrameworkTemplate.FindName内部没有直接调用VisualTreeHelper,它是利用缓存查找的。

逻辑树的用途

借助逻辑树,内容模型可以方便地循环访问其可能的子对象,从而实现扩展。

FrameworkElement提供了一个FindName的方法,可以通过名称查找子对象

1 public object FindName(string name);

它内部的实现实际就是借助的逻辑树

1 internal object FindName(string name, out DependencyObject scopeOwner)
2 {
3     INameScope scope = FindScope(this, out scopeOwner);
4     if (scope != null)
5     {
6         return scope.FindName(name);
7     }
8     return null;
9 }

 1 internal static INameScope FindScope(DependencyObject d, out DependencyObject scopeOwner)2 {3     while (d != null)4     {5         INameScope scope = NameScope.NameScopeFromObject(d);6         if (scope != null)7         {8             scopeOwner = d;9             return scope;
10         }
11         DependencyObject parent = LogicalTreeHelper.GetParent(d);
12         d = (parent != null) ? parent : Helper.FindMentor(d.InheritanceContext);
13     }
14     scopeOwner = null;
15     return null;
16 }

示例代码

参考链接:

https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/trees-in-wpf?view=netframeworkdesktop-4.8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/407644.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringCache源码解析(一)

一、springCache如何实现自动装配 SpringBoot 确实是通过 spring.factories 文件实现自动配置的。Spring Cache 也是遵循这一机制来实现自动装配的。 具体来说,Spring Cache 的自动装配是通过 org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration 这个类来…

Maven的使用

Maven 是一个项目管理工具&#xff0c;它基于项目对象模型&#xff08;POM&#xff0c;Project Object Model&#xff09;的概念&#xff0c;通过一小段描述信息&#xff08;pom.xml&#xff09;来管理项目的构建、报告和文档。Maven 提供了一个标准化的方式来构建项目&#xf…

MyBatis-Plus 三、(进阶使用)

一、typeHandler 的使用 1、存储json格式字段 如果字段需要存储为json格式&#xff0c;可以使用JacksonTypeHandler处理器。使用方式非常简单&#xff0c;如下所示&#xff1a; 只需要加上两个注解即可&#xff1a; TableName(autoResultMap true) 表示自动…

第五节:Nodify 节点位置设置

引言 如果你尝试过前几节的代码&#xff0c;会发现节点都是出现在0,0 位置&#xff0c;及编辑器左上角。编辑器作为最外层的交互控件&#xff0c;内部封装了节点容器ItemContrainer&#xff0c;我们通过样式属性对Loaction做绑定。本节将介绍如何配置节点位置。 1、节点位置 …

DHCP DNS 欺骗武器化——实用指南

DHCP 枚举 在我们之前的文章中,我们分享了 DHCP DNS 欺骗背后的理论。实际上,需要几条信息才能有效地执行我们描述的攻击。对于攻击者来说幸运的是,发现DHCP 服务器并了解其配置的能力是 DHCP 协议的一部分,这使得侦察过程变得微不足道。 在以下章节中,我们将描述攻击者…

Git的使用教程及常用语法02

四.将文件添加到仓库 创建仓库 git init查看仓库的状态 git status 添加到暂存区 git add提交 git commitgit status 可以查看当前仓库的状态信息&#xff0c;例如包含哪些分支&#xff0c;有哪些文件以及这些文件当前处在怎样的一个状态。 由于当前没有存储任何的东西&…

基于Python的机器学习系列(7):多元逻辑回归

在本篇博文中&#xff0c;我们将探讨多元逻辑回归&#xff0c;它是一种扩展的逻辑回归方法&#xff0c;适用于分类数量超过两个的场景。与二元逻辑回归不同&#xff0c;多元逻辑回归使用Softmax函数将多个类别的概率输出映射到[0, 1]范围内&#xff0c;并确保所有类别的概率和为…

PMBOK® 第六版 控制范围

目录 读后感—PMBOK第六版 目录 结果固然重要&#xff0c;过程同样不可或缺。过程不仅是通往预期成果的途径&#xff0c;也是个人和团队能力提升与经验积累的关键阶段。过程中的每一步都是学习和成长的机会&#xff0c;每一次尝试都能激发创新&#xff0c;而公正透明的流程更增…

TCP BBR 数学模型完整版

今天顺带加入了 bbr 的所有状态和所有流程&#xff0c;获得以下的方程组&#xff1a; C Bltbw&#xff0c;R RtProp&#xff0c;T_r ProbeRTT 周期&#xff0c;g1 Startup gain&#xff0c;g2 ProbeBW gain。设 x estimated bandwidth&#xff0c;r round trip time&am…

MySQL 数据库深度解析:安装、语法与高级查询实战

一、引言 在现代软件开发和数据管理领域中&#xff0c;MySQL 数据库凭借其高效性、稳定性、开源性以及广泛的适用性&#xff0c;成为了众多开发者和企业的首选。无论是小型项目还是大型企业级应用&#xff0c;MySQL 都能提供可靠的数据存储和管理解决方案。本文将深入探讨 MyS…

系统编程-lvgl

带界面的MP3播放器 -- lvgl 目录 带界面的MP3播放器 -- lvgl 一、什么是lvgl&#xff1f; 二、简单使用lvgl 在工程中编写代码 实现带界面的mp3播放器 main.c events_init.c events_init.h 补充1&#xff1a;glob函数 补充2&#xff1a;atexit函数 一、什么是lvgl&a…

安科瑞ACREL-7000能源管控平台在综合能耗监测系统在大型园区的应用

摘要&#xff1a;大型综合园区已经成为多种能源消耗的重要区域&#xff0c;为了探索适用于大型综合园区的综合能耗监测系统&#xff0c;建立了综合能耗监测系统整体框架&#xff0c;提出了综合能耗网络、能耗关系集合、能耗均衡度等概念&#xff0c;并以某大型综合园区为例对综…

AIGC综合应用-黑神话悟空创意写真大片制作方法(实操附模型文件)

​ 怎么用AI来制作 这种黑悟空的现代时尚大片&#xff1f; 悟空不再只是传统的西游记形象&#xff0c;而是走上现代时尚的T台&#xff0c;成为时尚大片中的主角。这个创意乍一听似乎有些离奇&#xff0c;但通过AI技术的加持&#xff0c;这一切都能轻松实现。不需要昂贵的拍摄设…

自编码器(Autoencoder, AE):深入理解与应用

自编码器&#xff08;Autoencoder, AE&#xff09;&#xff1a;深入理解与应用 引言 自编码器&#xff08;Autoencoder, AE&#xff09;是一种通过无监督学习方式来学习数据有效表示的神经网络模型。其核心思想是通过编码器将输入数据压缩成低维潜在表示&#xff0c;然后通过…

dokcer 安装 redis(单机版)

准备工作 拉取redis镜像 docker pull redis 通过docker-compose 安装redis 很方便、很简单 先安装docker&#xff0c;参考我这个安装示例进行安装 https://blog.csdn.net/qq_33192671/article/details/13714973 然后安装docker-compose&#xff0c;要是拉取docker-compose无…

低代码与AI:赋能企业数字化转型

引言 随着全球经济的快速发展和科技的飞速进步&#xff0c;数字化转型已成为各个行业和企业发展的重要趋势。数字化转型的背景不仅是提升效率和竞争力的手段&#xff0c;更是适应市场变化、满足客户需求的必由之路。 在当今信息化时代&#xff0c;技术的变革推动了企业运营方式…

Java语言程序设计——篇十七(1)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

探索人工智能的未来:埃里克·施密特2024斯坦福大学分享六

代理与文本生成模型的未来展望 您认为明年代理或文本生成模型会出现通货膨胀点吗&#xff1f; 不&#xff0c;不会。 我听到了类似的观点&#xff0c;尤其是埃里克科维茨的看法。他有一个很好的方式来阐述这三个趋势。虽然我之前也听说过这些趋势&#xff0c;但将它们整合起…

helm安装jenkins保姆级别

一、创建nfs服务器 这一步跳过、自行百度 注意&#xff1a;要给共享目录赋予权限chmod一下&#xff0c;不然到时候容器没办法在目录里面创建文件&#xff0c;初始化时候会报错误代码2 二、添加Jenkins的Helm仓库 helm repo add jenkinsci https://charts.jenkins.io helm re…

python dash框架 油气田可视化软件设计文档

V1.1:机器学习框架(神经网络) 时间范围优化 表格布局优化 添加前端设计元素布局 V1.0&#xff1a;基础布局和对应计算函数 要求 首先第一部分是通过神经网络预测天然气流量&#xff0c;其中输入开始时间和截止时间是为了显示这一段时间内的天然气流量预测结果 第二部分&…