2011-02-03 67 views
1

如何连接在控件模板中进行动画的自定义控件属性?在动画中使用自定义控件属性

我正在创建一个具有几种状态的自定义按钮,并且我想在状态更改时为按钮文本的颜色设置动画。通常,文本是灰色的,并且在MouseOver上变为黑色。

我创建了一个NormalTextBrush为黑色文本和FadedTextBrush为灰色文本:

<SolidColorBrush x:Key="NormalTextBrush" Color="Black" /> 
<SolidColorBrush x:Key="FadedTextBrush" Color="DarkSlateGray" /> 

到目前为止,一切都很好。我的动画无误地运行。当鼠标移过按钮时,文本从灰色变为黑色。但是我真正想要做的是让使用该控件的开发人员指定文本颜色。

因此,我重新定义了两个文本画笔作为绑定到控件的Foreground属性。 FadedTextBrush使用值转换器来淡化前景色。重新定义的资源如下所示:

<SolidColorBrush x:Key="NormalTextBrush" Color="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" /> 
<SolidColorBrush x:Key="FadedTextBrush" Color="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ColorConverter}, ConverterParameter='1.2'}" /> 

这就是我遇到麻烦的地方。 WPF不允许绑定控件模板中的动画。它会抛出一个异常,并显示消息“无法冻结此Storyboard时间轴树以供跨线程使用”。该问题记录在here

这使我想到了我的问题:如何设置我的画笔资源,以便它们连接到Foreground属性,但仍然可以在控制模板中使用动画。

任何人都可以回答这个问题,下次见到你我会给你买一瓶啤酒!谢谢你的帮助。

回答

0

你必须用可用的工具来完成。我会建议占据相同屏幕空间的两个文本块,然后操作故事板中每个文本块的不透明度。下面是如何覆盖两个文本块,其中最上面的一个是在默认状态下是透明:

<Grid> 
    <TextBlock x:Name="textBlock1" Foreground="Black" 
     Margin="{TemplateBinding Padding}" 
     VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
     HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
     SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
     Text="{TemplateBinding Content}"/> 
    <TextBlock x:Name="textBlock2" Foreground="Gray" 
     Margin="{TemplateBinding Padding}" 
     VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
     HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
     SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
     Text="{TemplateBinding Content}" Opacity="0"/> 
</Grid> 

然后建立一个视觉状态组的可视状态管理器来交换他们不透明度:

<VisualStateGroup x:Name="CommonStates"> 
    <VisualStateGroup.Transitions> 
     <VisualTransition GeneratedDuration="0:0:0.5"/> 
    </VisualStateGroup.Transitions> 
    <VisualState x:Name="Normal"/> 
    <VisualState x:Name="MouseOver"> 
     <Storyboard> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBlock1"> 
       <EasingDoubleKeyFrame KeyTime="0" Value="0"/> 
      </DoubleAnimationUsingKeyFrames> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBlock2"> 
       <EasingDoubleKeyFrame KeyTime="0" Value="1"/> 
      </DoubleAnimationUsingKeyFrames> 
     </Storyboard> 
    </VisualState> 
    <VisualState x:Name="Pressed"/> 
    <VisualState x:Name="Disabled"/> 
</VisualStateGroup> 

或者你可以使用你自己的故事板。重点是我们现在使用故事板操作常量值,但是您可以使用您选择的任何方法设置每个状态的文本块的前景。

+0

我接受了这个回答,因为它确实回答了我提出的问题。但我认为有一个更简单的解决方案 - 我将转储状态更改动画并使用样式触发器执行无动画状态更改。 – 2011-02-04 15:56:03