WPF-Binidng在ControlTemplate 内会失效的问题
{Binding}在ControlTemplate里经常失效,并不是Binding写错了,而是ControlTemplate里的元素根本没有DataContext.
一、一个失效的例子:
<ControlTemplate TargetType="Button">
<TextBlock Text="{Binding Title}"/>
</ControlTemplate>em……,这里可能会想:“Button在页面上”,Button的DataContext是ViewModel,那ControlTemplate 内的TextBlock应该也能绑定到ViewModel的Title吧?
这是不对的
分析下失效的原因或者说这里具体发生了什么:
首先要清楚 ControlTemplate内的元素不在逻辑树,不继承外部的DataContext,DataContext默认是null。
可这样说:
此时{Binding}什么也绑定不到,所以看起来就好似“失效”了
二、那么在ControlTemplate内该怎么写Binding呢?
规则1:模板里绑定控件自身属性–使用 TemplateBinding
<Border Background="{TemplateBinding Background}"/>规则2:用 RelativeSource TemplatedParent
<TextBlock
Text="{Binding Content,
RelativeSource={RelativeSource TemplatedParent}}"/>等价于:“绑定到应用了这个模板的控件”
一个常见的错误写法:
<TextBlock Text="{Binding Content}"/>因为:DataContext是null,Binding无法解析
三、{Binding}在ControlTemplate内什么时候能用?
情况:ControlTemplate内部某个元素自己“被显式设置了DataContext”
例如:
<ControlTemplate TargetType="Button">
<Grid DataContext="{TemplateBinding Content}"
<TextBlock Text="{Binding}"/>
</Grid>
</ControlTemplate>此时:Grid.DataContext = Button.Contet,DataContext不为null,{Binding} 自然就有了意义。
四、官方模板写法
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>为什么不直接写 Content="{Binding}"?
因为 ContentPresenter必须绑定的是 控件属性 ,不是DataContext.
五、对于上述的所有,WPF为什么要这样设计?
目的:ControlTemplate是“控件外观”,不是“业务视图”
如果ControlTemplate能随意访问ViewModel,那么一个Button的外观和业务就耦合了,模板将不可复用,控件库会直接废掉,
所以 WPF 强制:模板只能认识“控件自己”,不能认识“外部数据”
六、使用武侠进行总结:
ControlTemplate:“统一发的门派制服”
它只能知道:衣服尺寸(控件属性),颜色(控件属性),样式(控件属性)
它不知道:穿衣服的人是谁(ViewModel),这个人的身份、名字、背景
所以 {Binding} 就等于 “我想用当前人的内力” 但你 根本不知道这个人是谁 –> 失败,正确的方式是“用这件衣服本身的属性”
最后:在 ControlTemplate 内 Binding 时,ControlTemplate 不认 DataContext,只认自己 TemplatedParent,要么TemplateBinding,要么 RelativeSource.