正确理解WPF中的TemplatedParent
http://www.cnblogs.com/mgen/archive/2011/08/31/2160581.html
(注:Logical Tree中文称为逻辑树,Visual Tree中文称为可视化树或者视觉树,由于名称不是很统一,文中统一用英文名称代表两个概念,况且VisualTreeHelper和LogicalTreeHelper也是WPF中提供的类名称)
众所周知WPF中的Logical Tree是逻辑上定义的元素层次树,而实际上显示在屏幕上的元素层次树是Visual Tree,Visual Tree是Logical Tree节点扩充后的的产物。因此从Visual Tree的角度上看(Visual Tree当然是完整的一个),Logical Tree被分割成一段一段的,而这些段与段的连接点,就是和TemplatedParent有关。
这个概念在WPF类模型中是FrameworkElement.TemplatedParent属性。WPF中的模板(数据模板和控件模板)都可以扩展Logical Tree,那么模板所修饰的对象就是模板中元素的TemplatedParent,此时模板元素和修饰对象都会出现在Visual Tree中,但模板元素肯定不属于被修饰元素的Logical Tree,但是模板有自己的Logical Tree,两个Logical Tree是分开的,但是通过TemplatedParent,两者之间又有联系。
说再多不如实例形象,来看下面示例代码:
这是一个简单的ContentControl,它的Content是一个按钮,然后定义了控件模板和数据模板,代码中一些关键元素有Name属性,我们在后续讨论就以Name属性的值来引用这些元素。
<ContentControl Name="contentControl">
<!-- 控件模板 -->
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Border Name="bd1">
<ContentPresenter Name="cp1" ContentSource="Content"/>
</Border>
</ControlTemplate>
</ContentControl.Template>
<!-- 数据模板 -->
<ContentControl.ContentTemplate>
<DataTemplate>
<Border Name="bd2">
<ContentPresenter Name="cp2" Content="{Binding}" />
</Border>
</DataTemplate>
</ContentControl.ContentTemplate>
<!-- 逻辑孩子 -->
<Button Name="btn">按钮</Button>
</ContentControl>
这个ContentControl的Visual Tree如下图:
图中相同颜色的节点代表它们属于同一个Logical Tree,可以看出来,整个Visual Tree分成多个Logical Tree,而这些Logical Tree是分开的,比如上面代码中的两个Border(名称是bd1和bd2),它们的Parent属性的值都是null,即没有逻辑父节点。但是这些逻辑树通过TemplatedParent是互相有联系的。比如控件模板中的元素的TemplatedParent指代最上方的ContentControl,而数据模板元素的TemplatedParent则是控件模板内的ContentPresenter元素。
通过代码也可以验证这些:(bd1, bd2, cp1, cp2分别代表控件模板和数据模板中的Border和ContentPresenter)
private void Button_Click(object sender, RoutedEventArgs e)
{
var bd1 = (Border)contentControl.Template.FindName("bd1", contentControl);
var cp1 = (ContentPresenter)contentControl.Template.FindName("cp1", contentControl);
var bd2 = (Border)contentControl.ContentTemplate.FindName("bd2", cp1);
var cp2 = (ContentPresenter)contentControl.ContentTemplate.FindName("cp2", cp1);
PrintInfo(bd1, cp1, bd2, cp2, btn);
}
void PrintInfo(params FrameworkElement[] eles)
{
string s = "";
foreach (var ele in eles)
s += String.Format("{2}\r\nParent: {0}\r\nTemplatedParent: {1}\r\n\r\n", ele.Parent, ele.TemplatedParent, ele.Name);
MessageBox.Show(s);
}
输出信息:(冒号后没有值则代表null)
bd1
Parent:
TemplatedParent: System.Windows.Controls.ContentControl: 按钮
cp1
Parent: System.Windows.Controls.Border
TemplatedParent: System.Windows.Controls.ContentControl: 按钮
bd2
Parent:
TemplatedParent: System.Windows.Controls.ContentPresenter
cp2
Parent: System.Windows.Controls.Border
TemplatedParent: System.Windows.Controls.ContentPresenter
btn
Parent: System.Windows.Controls.ContentControl: 按钮
TemplatedParent:
最后还有一个btn,指代ContentControl中的内容按钮,它属于主干逻辑树,因此Parent是ContentControl,同时它也不属于任何模板,不存在修饰对象,因此TemplatedParent为null
另外WPF数据绑定Binding类还支持RelativeSource对象,这个RelativeSource类的Mode属性有一个TemplatedParent值,这个值就是代表数据绑定会将数据源作为,同时WPF中的TemplateBinding标记扩展可以方便定义此类绑定,另外TemplateBinding的绑定模式是OneWay。
了解了TemplatedParent,使用TemplateBinding也就非常灵活了,一般情况下TemplateBinding使用在定义控件模板下,但是在数据模板中也可以使用,比如下面这个例子:
<ContentControl>
<Button>Content</Button>
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}" />
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
这个TemplateBinding的数据源在哪里?答案就是ContentControl中默认控件模板里的ContentPresenter,所以这里数据模板内的ContentPresenter的Content直接绑定到控件模板中的ContentPresenter的Content属性,当然这个仅仅为了做示例,实际上用Content=”{Binding}”也可以。
正确理解WPF中的TemplatedParent相关推荐
- 理解WPF中的视觉树和逻辑树
理解WPF中的视觉树和逻辑树 Understanding the Visual Tree and Logical Tree in WPF 这篇文章讨论WPF中视觉树和逻辑树的细微差别.同时提供了一个 ...
- python的上下文管理用哪个关键字_正确理解python中的关键字“with”与上下文管理器...
正确理解python中的关键字"with"与上下文管理器 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: 正确理解python中的关键字&quo ...
- 如何理解WPF中的样式(Style)与模板ControlTemplate
1.如何理解WPF中的Style Style作用: a.样式设置,用来为一组相同控件设置统一的样式 b.只能改变控件的已有属性值(比如颜色字体) 样式 作用 Style Style.Resource ...
- matlab计算正负零序分量,5分钟教你正确理解电力系统中的正序负序零序.doc
5分钟教你正确理解电力系统中的正序负序零序 电力 三相不平衡 作图法 对称分量法 1:三相不平衡的的电压(或电流),可以分解为平衡的正序.负序和零序 2:零序为3相电压向量相加,除以3 3:正序将BC ...
- 正确理解scipy中的coo_matrix函数
正确理解scipy中的coo_matrix函数 1. 构造一个空矩阵 2. 使用ijv(triplet)格式构造一个矩阵 3. 用重复的索引构造矩阵 1. 构造一个空矩阵 这种用法比较简单,直接生成一 ...
- 2.如何正确理解古典概率中的条件概率《zobol的考研概率论教程》
写本文主要是帮助粉丝理解考研中的古典概率-条件概率的具体定义. "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约 ...
- mysql having in_正确理解MySQL中的where和having的区别
以前在学校里学习过SQLserver数据库,发现学习的都是皮毛,今天以正确的姿态谈一下MySQL中where和having的区别. 误区:不要错误的认为having和group by 必须配合使用. ...
- 正确在WPF中对Windows窗体背景进行设置
初次接触WPF,就被对窗体的背景图进行设置难住了.跟Winform区别很大, 如果没有正确设置的,会报错. 直接输入添加背景图片代码会弹出异常. <Window.Background> & ...
- 在MySQL中 NULL的含义是_null有哪些常见的意思?(如何正确理解 SQL 中的 NULL)
SELECT * FROM SOME_TABLEWHERE SOME_COLUMN IS NULL 或者这样写: 复制代码WHERE SOME_COLUMN = 1 正确的写法应该是第二种(WHER ...
最新文章
- manjaro升级的一些问题
- win7 右键菜单增加“在此以管理模式运行命令行”
- Apache服务器学习笔记
- java 运行os文件路径_Java获取文件路径的几种方式
- python中excel制作成绩报表_python制作简单excel统计报表2之操作excel的模块openpyxl简单用法...
- 前端学习(2638):读懂代码之登录页login.vue之ref和rules
- vb net的定时循环_.NET工具ReSharper:如何帮助Visual Studio用户?
- 随想录(如何学习内核)
- JSON --- JAVA 使用方法
- VSCode 扩展中出现严重漏洞,可导致供应链攻击
- 我是如何战胜懒惰的?
- 随机森林、极端随机森林以及深度森林代码
- python怎么输出roc曲线_如何用Python绘制ROC曲线
- 微软校园招聘面试经历
- js rsa java解密_RSA使用js加密,使用java解密
- java 金额的大小写转换类
- 交换机环路故障排查秘籍
- 怎么做软件开发,软件开发流程八个步骤
- 如何解决数据关联查询
- 视频流解码播放之VLC
热门文章
- php mysql ajax登录界面_PHP+jQuery+Ajax实现用户登录与退出
- python列表定义和操作_Python 列表的定义及操作
- mysql 参照完整性规则_MySQL存储引擎你们知道多少?
- 人口会一直增长下去吗_一直善良下去,你就会幸福
- ajax同步、异步区别及应用
- 谷歌提出新型自动语音识别数据增强大法,直接对频谱图“动刀”,提升模型表现...
- 国内首批AI专业毕业生创办的澎思科技,已完成Pre-A轮融资
- 你的GAN再不听话,就把它暴力肢解了吧,有用 | Demo · 代码
- 又一所小而精研究型大学!中科院与深圳共建,设AI等专业
- 迁移学习比赛:OpenAI喊你重温「音速小子索尼克」