原文:正确理解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相关推荐

  1. 理解WPF中的视觉树和逻辑树

    理解WPF中的视觉树和逻辑树  Understanding the Visual Tree and Logical Tree in WPF 这篇文章讨论WPF中视觉树和逻辑树的细微差别.同时提供了一个 ...

  2. python的上下文管理用哪个关键字_正确理解python中的关键字“with”与上下文管理器...

    正确理解python中的关键字"with"与上下文管理器 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  正确理解python中的关键字&quo ...

  3. 如何理解WPF中的样式(Style)与模板ControlTemplate

    1.如何理解WPF中的Style Style作用: a.样式设置,用来为一组相同控件设置统一的样式 b.只能改变控件的已有属性值(比如颜色字体) 样式 作用 Style Style.Resource ...

  4. matlab计算正负零序分量,5分钟教你正确理解电力系统中的正序负序零序.doc

    5分钟教你正确理解电力系统中的正序负序零序 电力 三相不平衡 作图法 对称分量法 1:三相不平衡的的电压(或电流),可以分解为平衡的正序.负序和零序 2:零序为3相电压向量相加,除以3 3:正序将BC ...

  5. 正确理解scipy中的coo_matrix函数

    正确理解scipy中的coo_matrix函数 1. 构造一个空矩阵 2. 使用ijv(triplet)格式构造一个矩阵 3. 用重复的索引构造矩阵 1. 构造一个空矩阵 这种用法比较简单,直接生成一 ...

  6. 2.如何正确理解古典概率中的条件概率《zobol的考研概率论教程》

    写本文主要是帮助粉丝理解考研中的古典概率-条件概率的具体定义. "B事件发生的条件下,A事件发生的概率"? "在A集合内有多少B的样本点"? "在B约 ...

  7. mysql having in_正确理解MySQL中的where和having的区别

    以前在学校里学习过SQLserver数据库,发现学习的都是皮毛,今天以正确的姿态谈一下MySQL中where和having的区别. 误区:不要错误的认为having和group by 必须配合使用. ...

  8. 正确在WPF中对Windows窗体背景进行设置

    初次接触WPF,就被对窗体的背景图进行设置难住了.跟Winform区别很大, 如果没有正确设置的,会报错. 直接输入添加背景图片代码会弹出异常. <Window.Background> & ...

  9. 在MySQL中 NULL的含义是_null有哪些常见的意思?(如何正确理解 SQL 中的 NULL)

    SELECT * FROM SOME_TABLEWHERE SOME_COLUMN IS NULL 或者这样写: 复制代码WHERE SOME_COLUMN = 1 正确的写法应该是第二种(WHER ...

最新文章

  1. manjaro升级的一些问题
  2. win7 右键菜单增加“在此以管理模式运行命令行”
  3. Apache服务器学习笔记
  4. java 运行os文件路径_Java获取文件路径的几种方式
  5. python中excel制作成绩报表_python制作简单excel统计报表2之操作excel的模块openpyxl简单用法...
  6. 前端学习(2638):读懂代码之登录页login.vue之ref和rules
  7. vb net的定时循环_.NET工具ReSharper:如何帮助Visual Studio用户?
  8. 随想录(如何学习内核)
  9. JSON --- JAVA 使用方法
  10. VSCode 扩展中出现严重漏洞,可导致供应链攻击
  11. 我是如何战胜懒惰的?
  12. 随机森林、极端随机森林以及深度森林代码
  13. python怎么输出roc曲线_如何用Python绘制ROC曲线
  14. 微软校园招聘面试经历
  15. js rsa java解密_RSA使用js加密,使用java解密
  16. java 金额的大小写转换类
  17. 交换机环路故障排查秘籍
  18. 怎么做软件开发,软件开发流程八个步骤
  19. 如何解决数据关联查询
  20. 视频流解码播放之VLC

热门文章

  1. php mysql ajax登录界面_PHP+jQuery+Ajax实现用户登录与退出
  2. python列表定义和操作_Python 列表的定义及操作
  3. mysql 参照完整性规则_MySQL存储引擎你们知道多少?
  4. 人口会一直增长下去吗_一直善良下去,你就会幸福
  5. ajax同步、异步区别及应用
  6. 谷歌提出新型自动语音识别数据增强大法,直接对频谱图“动刀”,提升模型表现...
  7. 国内首批AI专业毕业生创办的澎思科技,已完成Pre-A轮融资
  8. 你的GAN再不听话,就把它暴力肢解了吧,有用 | Demo · 代码
  9. 又一所小而精研究型大学!中科院与深圳共建,设AI等专业
  10. 迁移学习比赛:OpenAI喊你重温「音速小子索尼克」