TemplateBinding与Binding区别,以及WPF自定义控件开发的遭遇
在上一次的文章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自定义控件开发的遭遇相关推荐
- TemplateBinding和Binding的区别
TemplateBinding是单方向的,即数据源到目标的方向 当数据源的类型和目标的类型不一致时,TemplateBinding需要自己写转换器来完成. TemplateBinding与Bindin ...
- WPF 用户控件和 WPF自定义控件区别
WPF 用户控件 将多个现有的控件组合成一个可重用的"组". 由一个XAML文件和一个后台代码文件. 不能使用样式和模板. 继承自UserControl类. WPF自定义控件(扩展 ...
- 基于WPF的开发的知识点
基于WPF的开发 一.XAML 语言 XAML被编译为BAML(Binary Application Markup Language)文件.通常,BAML文件比XAML更小,编译后的BAML都是Pre ...
- 【转】WPF自定义控件与样式(3)-TextBox RichTextBox PasswordBox样式、水印、Label标签、功能扩展...
一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要是对文本输入控件进行样式开发,及相关扩展功能开发,主要内容包括: 基本文 ...
- [WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 原文:[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 1. 前言 WPF有一个灵活的 ...
- WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...
- WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
原文:WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐 ...
- WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
原文:WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等, ...
- [WPF自定义控件库]自定义Expander
[WPF自定义控件库]自定义Expander 原文:[WPF自定义控件库]自定义Expander 1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过 ...
最新文章
- VS.net2008正式版发布了
- 《oracle大型数据库系统在AIX/unix上的实战详解》集中讨论42:在AIX环境下安装Oracle11gR1 文平...
- SAP战略中的机器学习
- 计算机网络·CSMA/CD协议有关计算
- 实战并发编程 - 08基于Guarded Suspension模式优化轮询while(true)
- Winform中实现右下角Popuo弹窗提醒效果(附代码下载)
- LeetCode 945. 使数组唯一的最小增量(贪心)
- java x.length_Java中的length和length()
- 使用Red Gate Sql Compare 数据库同步工具进行SQL Server的两个数据库的结构比较、同步...
- ZT 为什么pthread_cond_t要和pthread_mutex_t同时使用 || pthread/Linux多线程编程
- D. Magic Breeding
- 2021年中国车轮电机市场趋势报告、技术动态创新及2027年市场预测
- Luogu P2880 [USACO07JAN]平衡的阵容Balanced Lineup (ST表模板)
- 构建微服务体系结构的最佳实践
- blockUI弹出层
- python开发ps插件_【UI/UE】22款设计师必备的PS插件【附教程】
- SecureCRT 终端仿真程序 v7.0.0.326 中文绿色便携破解版
- 2010考研数学二第(20)题——多元积分学:二重积分计算
- 绘制流程图的基本规则
- win10安装ab测试工具
热门文章
- js 类数组arguments详解
- (二)spring MVC配置
- jquery JSON的解析方式
- 不同的容器里实现 RadioButton的单选
- Go学习笔记—Go并发基础
- strconv---用来基本类型之间的转换
- mysql 查找课程最高分_mysql 查询 学生id最高分的科目和日期
- java获取response数据_Java中实现Http请求并获取响应数据
- 深大计算机科学与技术在广东省,广东考生请注意:深圳大学2021年计划本省总招生人数比例超过75%!...
- 鸡尾酒排序算法c语言,[golang] 数据结构-鸡尾酒排序