在WPF中,当标签的值发生更改时,如何触发动画?

3

非常抱歉问这么基础的问题,我是WPF新手,一直在找几乎符合我需求的博客...

我有一个绑定了属性并且可以很好更新屏幕的标签,现在我想要一个小动画,每当该值被更新时就会闪烁标签的背景颜色。理想情况下,我希望有一个纯XAML的解决方案。

我看过DataTriggers,但似乎它们需要满足相等条件,而EventTriggers似乎无法附加到与数据显示相关的任何事件上。

谢谢 奥斯卡

3个回答

9

你是否应该使用事件触发器?在绑定中需要设置NotifyOnTargetUpdated=True,但是这在我的代码中有效。

<DataTemplate>
    <Border Name="templateBorder">
        <TextBlock Text="{Binding Path=Name, NotifyOnTargetUpdated=True}" />
    </Border>
    <DataTemplate.Triggers>
        <EventTrigger RoutedEvent="Binding.TargetUpdated">
            <BeginStoryboard>
                <Storyboard AutoReverse="True">
                    <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                                     To=".1" Duration="0:0:.5" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

无法让它正常工作...我正在使用与标签相同的东西...在事件触发器中,似乎没有触发RoutedEvent="Binding.Targetupdated"...我不需要在代码后台做任何事情吗? - MattE
不得不将TextBlock中的绑定更改为{Binding Path = DataContext.Name}才能使其正常工作。 - MattE

2
请检查下面的代码是否适用于您。标签的 Content 属性的任何更改都会产生动画效果。这是通过触发器和值转换器类完成的,该类将内容值转换为 "True" 或 "False",并设置触发器以对这两个值进行反应。转换器附加到标签的 Tag 属性,其连接到数据上下文的 Name 属性。此外,我还在鼠标进入和离开事件中添加了一些动画效果,这些效果非常简单,仅使用 XAML 中的路由事件完成。
转换器:
public class TestConverter : IValueConverter
{
    private string  _originalValue = String.Empty;
    private bool    _previousValue = false;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        _originalValue = (string)value;
        _previousValue = !_previousValue;
        return _previousValue.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return _originalValue;
    }
}

数据上下文初始化:

label1.DataContext = new Test() { Name = DateTime.Now.ToString() };

xaml:

<Window.Resources>
    <local:TestConverter x:Key="TestConverter" />
</Window.Resources>
<Grid>
    <Label             
        Height="28" 
        HorizontalAlignment="Left" 
        Margin="132,96,0,0" 
        Name="label1" VerticalAlignment="Top" Width="120">

        <Label.Content>
            <Binding Path="Name"/>
        </Label.Content>
        <Label.Tag>
            <Binding Path="Name" Converter="{StaticResource TestConverter}"/>
        </Label.Tag>
        <Label.Background>
            <SolidColorBrush x:Name="animatedBrush1" Color="Yellow" />
        </Label.Background>
        <Label.Style>
            <Style TargetType="Label">
                <Style.Triggers>
                    <Trigger Property="Tag" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard AutoReverse="True">
                                    <!--<DoubleAnimation 
                                        Storyboard.TargetProperty="FontSize" To="20"/>-->
                                    <DoubleAnimation 
                                        Storyboard.TargetProperty="Opacity" To="0.0" AutoReverse="True"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="Tag" Value="False">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard AutoReverse="True">
                                    <DoubleAnimation 
                                        Storyboard.TargetProperty="FontSize" To="20"/>
                                    <!--"<DoubleAnimation 
                                        Storyboard.TargetProperty="Opacity" To="0.0" AutoReverse="True"/>-->
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Label.Style>
        <Label.Triggers>
            <EventTrigger RoutedEvent="Label.MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation
                            Storyboard.TargetName="animatedBrush1"
                            Storyboard.TargetProperty="Color"
                            To="Blue" Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger RoutedEvent="Label.MouseLeave">
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation
                            Storyboard.TargetName="animatedBrush1"
                            Storyboard.TargetProperty="Color"
                            To="Yellow" Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Label.Triggers>
    </Label>
</Grid>

希望这可以帮助您,敬礼。

我在将动画更改为ColorAnimation时遇到了问题,属性Background.Color无效: 无法解析属性路径“Background.Color”中的所有属性引用。请验证适用对象是否支持这些属性。为什么在您的事件触发器中它可以正常工作,但在样式触发器中却不行?谢谢 Oskar - Oskar
好的,终于搞定了。问题在于 Label 上未分配 Background 属性(并且某种方式未继承),因此为 null。在标签上显式设置它可以正常工作,在包含标签的网格上设置它则不行。 - Oskar
请提供更多细节,说明您正在尝试做什么;也许可以创建一个新问题,并附上一些您的代码,以便我查看,谢谢。 - serge_gubenko

2

我喜欢serge_gubenko的答案,但是我想提到另一种我有时使用的技术。Serge的答案更接近您的“纯XAML”理想,因为它只有一个转换器,但这个答案的代码更少,可能更易读。 这是它:

在“Name”属性中添加一个PropertyChangedCallback,并从那里开始storyboard:

DependencyProperty NameProperty = DependencyProperty.Register( ..., new UIElementMetadata
{
  PropertyChangedCallback = (obj, e) =>
  {
    storyBoard.Begin();
  }
});

如果你不想在窗口首次加载时出现闪光,你可以添加一个标志:

...
  PropertyChangedCallback = (obj, e) =>
  {
    if(_initialized)
      storyBoard.Begin();
  }
...

protected override void OnInitialized(...)
{
  _initialized = true;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接