一、背景 

使用WPF的朋友,大家都很喜欢采用定义控件的公共样式,以便整个框架对该资源的使用,好处就是可以达到代码复用、系统风格统一等;

1. 定义资源

    <Style TargetType="Button" x:Key="ButtonStyle"><Setter Property="Content"><Setter.Value><Image Source="Imgs\btn.jpg"/></Setter.Value></Setter><Setter Property="Width" Value="60"/></Style>

2. 其他地方对该资源的引用:

    <StackPanel><Button Style="{DynamicResource ButtonStyle}"/><Button Style="{DynamicResource ButtonStyle}"/><Button Style="{DynamicResource ButtonStyle}"/></StackPanel>

该写法会出现一种情况,如下图所示(除了最后一个按钮能显示图片,而其他按钮却是“空白”,这让我的抑制不住我的好奇心,决定对该问题进行分析和思考:

二、代码实现 :分别采用三种写法来尝试

1. 采用原来Content的代码;(代码及图请参考上面)

2. 采用String来代替Content中的Image控件,具体代码和结果如下:

<Style TargetType="Button" x:Key="ButtonWithOutStringStyle"> 
         <Setter Property="Content" Value="Button"/> 
         <Setter Property="Width" Value="60"/> 
     </Style>

3. 采用ContentTemplate来代替Content属性,具体代码和结果如下:

    <Style TargetType="Button" x:Key="ButtonContentTemplateStyle"><Setter Property="ContentTemplate"><Setter.Value><DataTemplate><Image Source="Imgs\btn.jpg"/></DataTemplate></Setter.Value></Setter><Setter Property="Width" Value="60"/></Style>

结果出来了,这时能满足我的需求,但是我的好奇心更加强烈了,我非常想知道“为什么”?

三、分析 

我对以上3种情况,出现不同的结果非常好奇,我很想知道背后的运作原理;根据第一种情况,只有一个Button有图片,所以我进行了以下大胆的假设:

1. 假设出现该情况的原因是因为引用该资源的所有按钮使用了相同的一个Image控件,违背了“一个控件不能同存在可视树上两个不同节点上”;

2. 为什么String却可以正常显示;

3. ContentTemplate是渲染(呈现时)再进行实例化,所以显示的每个Image控件是不同的控件;

我带着这3个疑问进行了一步步的验证:

1. 验证:引用了ButtonStyle后是否使用了同一个对象;

    <StackPanel><Button x:Name="G_1_A" Style="{DynamicResource ButtonStyle}"/><Button x:Name="G_1_B" Style="{DynamicResource ButtonStyle}"/><Button x:Name="G_1_C" Style="{DynamicResource ButtonStyle}"/></StackPanel> Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_1_A.Name, G_1_A.Content.GetHashCode()));Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_1_B.Name, G_1_B.Content.GetHashCode()));Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_1_C.Name, G_1_C.Content.GetHashCode()));

结果如下:

2. 疑问:为什么采用String却可以,为了验证该问题,用了以前我写的一个工具“逻辑树与可视化树工具”;

错误图(之前验证方法有误,误导了大家),以下进行纠正

正确图(进行了树控件的优化)

错误结论:以上3个Button的Content(String)的HashCode都不一样,所以他们能正常显示出来;我开始还以为String是同一个,因为String在编译的时候,如果值是相同时会放入到驻留池中(这个出乎我的意料)

正确结论:3个Button的Content(String)的HashCode是一样的,因为string重写了GetHashCode方法 ,需要进一步确认是否是相同对象;

验证是否是同个对象:

Console.WriteLine(string.Format("{0} is {1}:{2}", G_2_A.Name, G_2_B.Name, object.ReferenceEquals(G_2_A.Content, G_2_B.Content)));

输出结果:证明string是同个对象,验证了string驻留池的说法是正确的;

G_2_A is G_2_B:True

3. 疑问:ContentTemplate是渲染(呈现时)再进行实例化,所以显示的每个Image控件是不同的控件;

3.1 我需要对G_3_A Button的Content和ContentTemplate进行分析

var content = G_3_A.Content;    
          var template = G_3_A.ContentTemplate;

结果如下:

3.2 我得到了一个结论是:ContentTemplate很有可能在渲染的时候才对Button的Content进行实例化,接下来的难题就是如何证明该观点:

我需要验证ContentTemplate里面的Content是否是同一个对象,结果如下:

Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_3_A.Name, G_3_A.ContentTemplate.LoadContent().GetHashCode()));    
          Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_3_B.Name, G_3_B.ContentTemplate.LoadContent().GetHashCode()));     
          Console.WriteLine(string.Format("{0}:\t{1}(HashCode)", G_3_C.Name, G_3_C.ContentTemplate.LoadContent().GetHashCode()));

结果如下:

3.3 证明ContentTemplate里面是不同的对象;我写下了如下代码:

var style = this.FindResource("ButtonContentTemplateStyle") as Style;    
           var setter = style.Setters[0] as Setter;     
           var template = setter.Value as DataTemplate;     
           Console.WriteLine(string.Format("第{0}次加载ButtonContentTemplateStyle:\tContent的HashCode({1})", count, template.LoadContent().GetHashCode())); 
          count++;

结果如下:

四、总结

WPF的树上是不允许有同一个控件存在两个不同的节点上;如果想要实现该功能,需要实例化两个对象然后存放到WPF的树上(包括逻辑树或可视化树);Silverlight也应该是一样的道理;WPF中的ContentControl定义样式时都不能采用Content来定义;

五、代码下载

点击下载代码

点击下载“逻辑树与可视化树工具”

  作者:SmlAnt

  出处:http://www.cnblogs.com/smlAnt

  注意:转载请保留以上内容,并标作者和出处。

【WPF】ContentControl Style定义与使用出现问题后 -- 引发的思考相关推荐

  1. Endnote 参考文献输出格式GB/T 7714的Style定义写法

    Endnote 参考文献输出格式GB/T 7714的Style定义写法 附录1 参考文献输出格式(GB/T 7714 <文后参考文献著录规则>) Author-Year Journal A ...

  2. linux右键菜单颜色,Linux_自定义右键菜单代码详解, style !-- /*定义菜单 - phpStudy...

    自定义右键菜单代码详解 < style > < !-- /*定义菜单方框的样式1*/ .skin0 { position:absolute; text-align:left; wid ...

  3. WPF中关于对前台Xaml中Triggers的一些重要思考。

    原文:WPF中关于对前台Xaml中Triggers的一些重要思考. 今天在做一个小Demo的时候碰到了一个比较奇怪的问题,就是其中一个Trigger始终无法执行,<Trigger Propert ...

  4. 哥德尔原著译本的前十四个定义——哥德尔读后之十三

    哥德尔原著译本的前十四个定义--哥德尔读后之十三 广州的疫情依然紧张,我校昨晚还包括今天早上,员工都在奔赴南操场进行自5月底以来的第二次核酸检测.因为疫情,差不多有一个月都蜷缩在家中了,顶多因为生活必 ...

  5. 从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第五讲 WPF中 Style

    Style这个东西几乎是无处不在,这个类似于web开发中的css样式,想要做一个很丰富的UI,这个东西是必不可少的,我也不是专业的UI开发者,这边只能介绍Style在WPF中的用法 下面有一个下载地址 ...

  6. wpf资源的定义与使用(String类型)

    wpf中基本上每个标签都有一个Resource属性,这个就是资源属性 但是我们一般是在window标签里面定义资源,因为资源就可以供所有标签使用了 1.定义资源(String类型) <Windo ...

  7. WPF的Style中的设置器Setter

    一.概述 Setters 是Style类中的一个重要属性. Setters 包含着 Setter 和 EventSetter 类的集合 Setter类的作用是给System.Windows.Style ...

  8. [WPF]在Style中设置ToolTip的问题分析

    刚才开到智者千虑发的[WPF]在Style中设置ToolTip的问题的博文,虽然最终给了一个暂时解决问题的方案,但是没有分析和解释其中的问题,正与他所说:但至于为什么不能直接在Setter.Value ...

  9. wpf 将Style应用到 ListView 中的 ListViewItem 元素

    例: 为每个条目元素设置右键菜单 1. 新建右键菜单元素和样式元素 注意: 同时设置样式元素的 TargetType 属性和 x:Key 属性, 将样式元素限定为应用于 ListViewItem 类型 ...

  10. 第7篇 WPF C# 怎样定义类及其接口

    1.概述 1.1 类和接口的本质 类和接口用于表述事物的特征,从而成为可编程的东西.也就是将物理存在的事物表述为编程可用的代码. 类提供一个好像标准模板一样的东西,通过实例化变成程序中各个不同的对象. ...

最新文章

  1. 赵雪轩:数据科学助力我的智能化航天梦 | 提升之路系列
  2. html5虚线绘制的函数,HTML5 Canvas绘制圆点虚线实例
  3. c++ static 存储类
  4. python2和3的编码区别_Python2和3字符编码的区别
  5. 使用BIND安装智能DNS服务器(一)---基本的主从DNS服务器搭建
  6. jeecg t:datagrid标签 每页显示条数 扩展
  7. 互联网“高薪榜”曝光,物联网将接棒?
  8. 从英伟达 vs ATI的芯片大战看GPU前世今生
  9. 大数据之-Hadoop3.x_MapReduce_自定义outputformat案例完善执行---大数据之hadoop3.x工作笔记0123
  10. mysql 导入设置编码_MySQL导入或导出数据库字符编码集设置
  11. 深入理解Javascript之this关键字
  12. Android音量控制器,音量控制器
  13. ZigBee技术[转]
  14. React使用iconfont阿里巴巴矢量图库
  15. 【爬虫】爬取百度搜索结果页面
  16. Linux服务器期末复习总结
  17. 3d max 安装及激活教程
  18. 关键词生成原创文章及句子的软件!开发原理分析
  19. UIQ 3 概念认识
  20. Spark创建DataFrame

热门文章

  1. 规则 防火墙 iptables input accept【转】
  2. 百度API开发中的误区记录
  3. C# 操作Active Directory (AD)的操作类
  4. 寒冬之下,互联网金融的数据化建设心得
  5. C#,入门教程(43)——字节、字符、字符串及操作函数之基础知识总结与实例源代码(2023清明之作)
  6. Vioovi ECRS工时分析软件:工序分析的得力助手
  7. PCL学习笔记(31)——使用积分图估计法线向量
  8. 华为认证知识点之IPV6
  9. MyBatis源码概述及运行原理解析(篇一)
  10. Linux下apache防恶意访问(攻击)脚本