在WPF中设置TextBox.Foreground的动画

时间:2013-08-24 21:59:41

标签: wpf animation textbox storyboard wpf-4.0

是否有动画TextBox.ForegroundProperty

<Color x:Key="NormalColor">#FF666666</Color>
<SolidColorBrush x:Key="NormalBrush" Color="{StaticResource NormalColor}" />

<Color x:Key="MouseOverColor">#FF666666</Color>
<SolidColorBrush x:Key="MouseOverBrush" Color="{StaticResource MouseOverColor}" />

<ControlTemplate x:Key="RegularTextBoxTemplate" TargetType="{x:Type TextBox}">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:0.1"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <!-- storyboard to animating foreground here... -->
                    </Storyboard>
                </VisualState>
            </VisualStateGroup >
        </VisualStateManager>
        <ScrollViewer x:Name="PART_ContentHost" 
                      BorderThickness="0"
                      IsTabStop="False"
                      Background="{x:Null}"/>
    </Grid>
</ControlTemplate>

<Style x:Key="RegularTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Foreground" Value="{StaticResource NormalBrush}"/>
    <Setter Property="Template" Value="{StaticResource RegularTextBoxTemplate}"/>
</Style>

我试过的故事板是:

<ColorAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentHost"
                  Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentHost"
              Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames Storyboard.TargetName="PART_ContentHost"
          Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames
                  Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames
              Storyboard.TargetProperty="(TextBox.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames
              Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

<ColorAnimationUsingKeyFrames
          Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

它们都不起作用。任何的想法?它甚至可能吗?

3 个答案:

答案 0 :(得分:9)

这比我想象的更成问题。这是我原来的答案:


这绝对是可能的 - 这就是ColorAnimationXXX类的用途。

您的代码与代码示例here非常相似,代码示例使用ColorAnimation为颜色设置动画。示例中的属性采用了一个Brush(就像TextBox.Foreground),它在XAML中定义并给出一个名称,以便动画可以轻松引用它。

因此,在您的情况下,相关的代码将是:

<VisualState Name="...">
   <Storyboard>
      <ColorAnimation To="Green" 
                      Storyboard.TargetName="tbBrush" 
                      Storyboard.TargetProperty="Color"/>
    </Storyboard>
</VisualState>

<TextBox.Foreground>
  <SolidColorBrush x:Name="tbBrush" Color="#FF666666"/>
</TextBox.Foreground>

理论上,这一切都非常好,直到我意识到它不是一种风格。而样式中Grid的Background属性很容易实现,例如:

Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)"

要找到一个对文本前景产生影响的动画属性要困难得多。最初我尝试TextElement.Foreground,看起来很直观,我能够在Grid和ScrollViewer级别设置这个属性,我期望它对下面的所有子对象产生影响 - 包括它在底层的任何对象它包含TextBox的文本。我的假设是TextBox内容将在内部设置为TextBlock,它将遵循其上设置的Foreground附加属性的值。似乎我的假设不正确,并且PART_ContentHost ScrollViewer的内容由TextBox中的控制逻辑设置为较低级别的对象,该对象不遵守顶级TextBox与其自身之间的对象树中的任何Foreground依赖属性。

问题是如何在要设置样式的TextBox样式中设置TextBox的Foreground属性。为了测试,我尝试使用TwoWay TemplatedParent绑定来设置它。我认为我将PropertyPath设置为SolidColorBrush的颜色,但它仍然无法正常工作,因为此时Color属性显然是不可变的。我相信此问题已记录在案here

除了它不起作用之外,在内部设置Foreground属性似乎并不正确,因为外部消费者期望控制该属性的值。因此,鉴于TextBox的前景不会遵循某个样式中的任何内容,我得出结论,该功能最好使用TextBox样式中的嵌套TextBox实现。外部样式包含状态管理器和大部分布局,然后内部TextBox具有自己的样式和控件模板,其设计仅用于显示文本位。外部样式能够设置内部TextBox的Foreground属性,内部的TextBox将遵循,而关键的外部属性可以在状态管理器中设置此值。

<ControlTemplate x:Key="RegularTextBoxTemplate" TargetType="{x:Type TextBox}"> 
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:0.1"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation To="HotPink"
                            Storyboard.TargetName="InternalTextBox"
                            Storyboard.TargetProperty="(TextBox.Foreground).(SolidColorBrush.Color)"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <TextBox Foreground="Black" Text="{TemplateBinding Text}" x:Name="InternalTextBox">
            <TextBox.Style>
                <Style TargetType="{x:Type TextBox}">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type TextBox}">
                                <Grid Background="{x:Null}">
                                    <ScrollViewer x:Name="PART_ContentHost"
                                        BorderThickness="0"
                                        IsTabStop="False"
                                        Background="{x:Null}" />
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TextBox.Style>
        </TextBox>
    </Grid>
</ControlTemplate>

<Style x:Key="RegularTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Template" Value="{StaticResource RegularTextBoxTemplate}"/>
</Style>

我有兴趣听听其他人对这种方法的评论,以及我是否有任何问题,我没有考虑过。基于我尝试解决问题并窥探最终的应用程序,这是我目前可以看到的最简单的解决方案。

答案 1 :(得分:7)

好吧,感谢所有想帮助我的人,我找到了答案。当我们将TextBox.Foreground属性设置为资源时,故事板无法为其设置动画。所以,风格应该是这样的:

<Style x:Key="RegularTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Foreground">
        <Setter.Value>
            <SolidColorBrush Color="{DynamicResource NormalColor}"/>
        </Setter.Value>
    </Setter>
    <Setter Property="Template" Value="{StaticResource RegularTextBoxTemplate}"/>
</Style>

这是我遇到的唯一问题。但需要记住一个注意事项。当我们想要在故事板中定位模板化父级时,不必绑定它。我们只需要离开它:

<!-- It's not necessary to set Storyboard.TargetName in storyboard -->
<!-- It will automatically target the TemplatedParent -->
<ColorAnimationUsingKeyFrames
              Storyboard.TargetProperty="(TextBox.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{DynamicResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

这适合我。


Here是一个有效的例子。

答案 2 :(得分:2)

您可以将Storyboard.Target绑定到TemplatedParent:

<ColorAnimationUsingKeyFrames
        Storyboard.Target="{Binding RelativeSource={RelativeSource TemplatedParent}}"
        Storyboard.TargetProperty="(TextBox.Foreground).(SolidColorBrush.Color)">
    <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverColor}" />
</ColorAnimationUsingKeyFrames>

不幸的是,我只能在正常的前景画笔在样式中设置并直接在TextBox元素上设置时才能使用它:

<TextBox Foreground="{StaticResource NormalBrush}" Style="{StaticResource RegularTextBox}" />

如果在样式中设置,则触发MouseOver状态会在不可变对象实例上抛出“无法动画'(0)。(1)'。” 编辑 :如果在初始化后再次设置TextBox前景,也会发生这种情况。