WPF中VisualStateGroup内如何正确使用TemplateBinding
VisualStateGroup的Storyboard动画属性中无法直接使用TemplateBinding,这是WPF的固有机制限制,也是代码中Alternate状态背景变透明的根本原因。
原因说明
TemplateBinding是专门为ControlTemplate可视化树元素优化的轻量绑定标记,仅支持对模板可视化树中直接挂载的元素做属性赋值,无法作用于Storyboard、Animation这类游离在可视化树外的Freezable对象。写在ColorAnimation.To属性上的TemplateBinding不会被正常解析,会返回Color类型的默认值Transparent,因此切换状态时背景显示为透明。
硬编码颜色值时不需要绑定解析,动画可以直接拿到常量值,因此可以正常工作。
修复方案
方案1:替换为TemplatedParent模式的全写Binding(改动最小)
TemplateBinding本质是RelativeSource为TemplatedParent的Binding的简写优化版,全写Binding支持Freezable对象场景下的绑定解析,仅需要修改Alternate状态下的ColorAnimation代码即可,无需改动后台逻辑:
<VisualState x:Name="Alternate"> <Storyboard> <ColorAnimation To="{Binding MyBackground, RelativeSource={RelativeSource TemplatedParent}}" Duration="0" Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color" /> </Storyboard> </VisualState>
方案2:使用VisualState.Setters直接赋值(适合无过渡动画场景)
如果状态切换是瞬间完成(当前代码中动画Duration为0,无过渡效果),可以不用Storyboard动画,直接通过VisualState.Setters给目标元素赋值,这个场景下TemplateBinding可以正常生效,代码更简洁:
该写法要求WPF版本不低于4.0
<VisualStateGroup Name="MyStates"> <VisualState x:Name="Default"> <VisualState.Setters> <Setter TargetName="PART_Box" Property="Background" Value="Red"/> </VisualState.Setters> </VisualState> <VisualState x:Name="Alternate"> <VisualState.Setters> <Setter TargetName="PART_Box" Property="Background"> <Setter.Value> <SolidColorBrush Color="{TemplateBinding MyBackground}"/> </Setter.Value> </Setter> </VisualState.Setters> </VisualState> </VisualStateGroup>
使用这个方案后,可以删掉Border里单独命名的BackgroundBrush资源,不需要通过动画修改画刷颜色。
内容的提问来源于stack exchange,提问作者Woodrow Barlow

