如何在ControlTemplate的Storyboard中动画TemplatedParent的Foreground属性?
解决WPF VisualState修改TemplatedParent Foreground的崩溃问题
你遇到的崩溃是因为Storyboard的Target属性不支持直接使用RelativeSource绑定——Storyboard在WPF的动画系统中是在独立上下文运行的,无法解析模板内的RelativeSource绑定。下面是正确的实现方式:
步骤1:修改VisualState中的动画代码
把原来针对ContentControl的Foreground动画,改成直接修改TemplatedParent的Foreground,通过Storyboard.TargetProperty指定路径即可:
<VisualState x:Name="MouseOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bd" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonHoverBackgroundBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bd" Storyboard.TargetProperty="Stroke"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonHoverBorderBrush}" /> </ObjectAnimationUsingKeyFrames> <!-- 正确修改TemplatedParent的Foreground的动画 --> <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="(TemplatedParent).Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightForegroundBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState>
步骤2:绑定ContentControl的Foreground到TemplatedParent
在你的ControlTemplate里,把ContentControl的Foreground设置为TemplateBinding:
<ContentControl x:Name="ContentControl" Foreground="{TemplateBinding Foreground}" ... />
为什么这样能生效?
Storyboard.TargetProperty="(TemplatedParent).Foreground":在ControlTemplate的上下文中,这个路径会直接指向应用该模板的控件(也就是你的Button)的Foreground属性,动画系统可以正确解析这个路径,不需要额外的绑定。- ContentControl通过
TemplateBinding继承Button的Foreground,所以当VisualState修改Button的Foreground时,ContentControl的前景色会自动同步,同时Button内部的自定义控件通过RelativeSource绑定Button的Foreground也会跟着变化,完全符合你的需求。
验证效果
当鼠标悬停在Button上时:
- Button的Foreground被动画修改为
LightForegroundBrush - ContentControl的Foreground通过TemplateBinding同步变化
- 你自定义的
SomeCustomControl通过RelativeSource绑定Button的Foreground,也会自动更新为LightForegroundBrush
这样修改后就不会出现崩溃,同时完美实现了你想要的联动效果。
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

