在上一次的文章WPF OnApplyTemplate 不执行 或者执行滞后的疑惑谈到怎么正确的开发自定义控件,我们控件的样式中,属性的绑定一般都是用TemplateBinding来完成,如下一个基本的按钮样式:

<Style x:Key="SimpleButton" TargetType="{x:Type Button}" BasedOn="{x:Null}"><Setter Property="FocusVisualStyle" Value="{DynamicResource SimpleButtonFocusVisual}"/><Setter Property="Background" Value="{DynamicResource NormalBrush}"/><Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><!-- We use Grid as a root because it is easy to add more elements to customize the button --><Grid x:Name="Grid"><Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"/><!-- Content Presenter is where the text content etc is placed by the control --><!-- The bindings are useful so that the control can be parameterized without editing the template --><ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/></Grid><!--Each state sets a brush on the Border in the template --><ControlTemplate.Triggers><Trigger Property="IsKeyboardFocused" Value="true"><Setter Property="BorderBrush" Value="{DynamicResource DefaultedBorderBrush}" TargetName="Border"/></Trigger><Trigger Property="IsMouseOver" Value="true"><Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/></Trigger><Trigger Property="IsPressed" Value="true"><Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/><Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/></Trigger><Trigger Property="IsEnabled" Value="true"/><Trigger Property="IsEnabled" Value="false"><Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/><Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/><Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>

我们看到,许多属性都是用TemplateBinding来完成的,也就是我们在使用控件和开发自定义控件时,都能够做到数据的展示数据的行为分开,使用数据驱动UI的思想,对于较复杂行为的控件,我们也可以在OnApplyTemplate方法中通过GetTemplateChild方法来获取到,当然,这个方法的执行时机是必须在布局过程中,如果在这之前就使用了内部的控件,那么必然会报Null错误。
所以一般的样式开发中,都是用TemplateBinding来完成,说说今天的遭遇。我就是开发一个分页控件,点击上一页,下一页的时候,当前的页码要能够跟着变化。显示这个页码的控件那就是TextBlock,TemplateBinding了PageIndex依赖属性。控件的后台代码中,对上一页下一页的事件,就是修改PageIndex的值。运行起来,页码不会跟着变化!好,修改成Binding方式,如下:

<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=PageIndex}"></TextBlock>

这样能够正常工作了。但是WPF自家的控件用的都是TemplateBinding,都没这问题,不甘心,继续网上找资料,发现一篇说是自定义的依赖属性使用TemplateBinding就是有问题的,这种bug微软怎么能不发现呢,并且这都.Net4.5了,内心感觉一定不是这样的,终于啊,找到问题所在了,并且是在一篇排版杂乱无章的小博客中找到的。

TemplateBinding作为一种性能优化后的Binding使用,据说是Binding比较耗资源,这个没有求证过,但是我的程序中那么多Binding,运行起来也不觉得慢啊,或者说是用在模板中的一种Binding优化方式。既然是优化过的,那么它就会少一些东西,其中一个是数据流动的方向。TemplateBinding是单方向的,即数据源到目标的方向。这也解释了TreeViewItem官方的样式中,那个三角形的小箭头,它对于是否展开(IsExpanded属性)的属性绑定用的就不是TempalteBinding,因为他不能反过去更新数据源啊。

<Style x:Key="SimpleTreeViewItem" d:IsControlPart="True" TargetType="{x:Type TreeViewItem}"><Setter Property="Background" Value="Transparent"/><Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/><Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/><Setter Property="Padding" Value="1,0,0,0"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type TreeViewItem}"><Grid><Grid.ColumnDefinitions><ColumnDefinition MinWidth="19" Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition/></Grid.RowDefinitions><!--注意这里--><ToggleButton x:Name="Expander" Style="{DynamicResource SimpleTreeViewItemToggleButton}" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/><Border Grid.Column="1" x:Name="Selection_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"><ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" x:Name="PART_Header" ContentSource="Header"/></Border><ItemsPresenter Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" x:Name="ItemsHost"/></Grid><ControlTemplate.Triggers><Trigger Property="IsExpanded" Value="false"><Setter Property="Visibility" Value="Collapsed" TargetName="ItemsHost"/></Trigger><Trigger Property="HasItems" Value="false"><Setter Property="Visibility" Value="Hidden" TargetName="Expander"/></Trigger><Trigger Property="IsSelected" Value="true"><Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" TargetName="Selection_Border"/><Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/></Trigger><MultiTrigger><MultiTrigger.Conditions><Condition Property="IsSelected" Value="true"/><Condition Property="IsSelectionActive" Value="false"/></MultiTrigger.Conditions><Setter Property="Background" Value="red" TargetName="Selection_Border"/><Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/></MultiTrigger><Trigger Property="IsEnabled" Value="false"><Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>

但是在分页控件的这个页码属性上,是不需要反方向更新数据源这个功能的。所以问题也不是这儿,但必须注意这一点,开发自定义控件的时候非常重要。

另外一个区别就是Converter,WPF中的Binding都是能够通过Converter来转换数据的,所以不管是TemplateBinding还是Binding都是够使用Converter来设置转换器,区别在于没有设置转换器的情况下,例如将int类型的数据绑定到TextBox的Text属性上,Binding会将值转换成字符串来显示,然而TemplateBinding就不会,这就是页码不能显示,也不会变化的原因。我立马弄了一个字符串类型页码依赖属性,TemplateBinding到这个Text属性上,可以工作了。但不会这么傻,再写一个转换器给TemplateBinding,这也是能够工作的。所以当数据源的类型和目标的类型不一致时,TemplateBinding需要自己写转换器来完成

总结一下TemplateBinding与Binding区别

(1)TemplateBinding只是单方向的数据绑定
(2)TemplateBinding不会自动转换数据类型

转载于:https://www.cnblogs.com/HelloMyWorld/p/6744894.html

TemplateBinding与Binding区别,以及WPF自定义控件开发的遭遇相关推荐

  1. TemplateBinding和Binding的区别

    TemplateBinding是单方向的,即数据源到目标的方向 当数据源的类型和目标的类型不一致时,TemplateBinding需要自己写转换器来完成. TemplateBinding与Bindin ...

  2. WPF 用户控件和 WPF自定义控件区别

    WPF 用户控件 将多个现有的控件组合成一个可重用的"组". 由一个XAML文件和一个后台代码文件. 不能使用样式和模板. 继承自UserControl类. WPF自定义控件(扩展 ...

  3. 基于WPF的开发的知识点

    基于WPF的开发 一.XAML 语言 XAML被编译为BAML(Binary Application Markup Language)文件.通常,BAML文件比XAML更小,编译后的BAML都是Pre ...

  4. 【转】WPF自定义控件与样式(3)-TextBox RichTextBox PasswordBox样式、水印、Label标签、功能扩展...

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括: 基本文 ...

  5. [WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互

    [WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 原文:[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 1. 前言 WPF有一个灵活的 ...

  6. WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...

  7. WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    原文:WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐 ...

  8. WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

    原文:WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等, ...

  9. [WPF自定义控件库]自定义Expander

    [WPF自定义控件库]自定义Expander 原文:[WPF自定义控件库]自定义Expander 1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过 ...

最新文章

  1. VS.net2008正式版发布了
  2. 《oracle大型数据库系统在AIX/unix上的实战详解》集中讨论42:在AIX环境下安装Oracle11gR1 文平...
  3. SAP战略中的机器学习
  4. 计算机网络·CSMA/CD协议有关计算
  5. 实战并发编程 - 08基于Guarded Suspension模式优化轮询while(true)
  6. Winform中实现右下角Popuo弹窗提醒效果(附代码下载)
  7. LeetCode 945. 使数组唯一的最小增量(贪心)
  8. java x.length_Java中的length和length()
  9. 使用Red Gate Sql Compare 数据库同步工具进行SQL Server的两个数据库的结构比较、同步...
  10. ZT 为什么pthread_cond_t要和pthread_mutex_t同时使用 || pthread/Linux多线程编程
  11. D. Magic Breeding
  12. 2021年中国车轮电机市场趋势报告、技术动态创新及2027年市场预测
  13. Luogu P2880 [USACO07JAN]平衡的阵容Balanced Lineup (ST表模板)
  14. 构建微服务体系结构的最佳实践
  15. blockUI弹出层
  16. python开发ps插件_【UI/UE】22款设计师必备的PS插件【附教程】
  17. SecureCRT 终端仿真程序 v7.0.0.326 中文绿色便携破解版
  18. 2010考研数学二第(20)题——多元积分学:二重积分计算
  19. 绘制流程图的基本规则
  20. win10安装ab测试工具

热门文章

  1. js 类数组arguments详解
  2. (二)spring MVC配置
  3. jquery JSON的解析方式
  4. 不同的容器里实现 RadioButton的单选
  5. Go学习笔记—Go并发基础
  6. strconv---用来基本类型之间的转换
  7. mysql 查找课程最高分_mysql 查询 学生id最高分的科目和日期
  8. java获取response数据_Java中实现Http请求并获取响应数据
  9. 深大计算机科学与技术在广东省,广东考生请注意:深圳大学2021年计划本省总招生人数比例超过75%!...
  10. 鸡尾酒排序算法c语言,[golang] 数据结构-鸡尾酒排序