基于 属性 的 WPF 动画开始时更改触发器

WPF animation based on property change triggers at start

当绑定到文本框文本 属性 的值发生变化时,我正在尝试为边框颜色设置动画:

<Border x:Name="border" BorderThickness="3" BorderBrush="Blue" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock Background="White" TextAlignment="Center" FontSize="24" 
                       Text="{Binding Value, NotifyOnTargetUpdated=True}">
        <TextBlock.Triggers>
            <EventTrigger RoutedEvent="Binding.TargetUpdated">
                <EventTrigger.Actions>
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation To="Yellow"
                                Storyboard.TargetName="border"
                                AutoReverse="True"
                                Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
                                FillBehavior="Stop"
                                Duration="0:0:0.5"
                                RepeatBehavior="5x" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger.Actions>
            </EventTrigger>
        </TextBlock.Triggers>
    </TextBlock>
</Border>

问题是即使在应用程序启动时动画也会被触发并且值尚未设置一次。 有没有办法避免这种情况?

这是我建议的解决方法的工作演示。这使用 AgentOctal.WpfLib Nuget 包(免责声明:我是这个包的作者)用于 ViewModel 基础 class 和 ICommand 实现,但您应该能够轻松地替换您使用的任何系统。

如果我为您找到更好的选择,我会将其添加为附加答案。

MainWindow.xaml(注意:TextBlock 上的 EventTrigger 已更改为 Border 上的 DataTrigger

<Window
    x:Class="BindingHelp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:BindingHelp"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="525"
    Height="350"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:MainWindowVm />
    </Window.DataContext>
    <StackPanel Orientation="Vertical">
        <Border
            x:Name="border"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            BorderBrush="Blue"
            BorderThickness="3">
            <Border.Style>
                <Style>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=ShouldAnimate}" Value="true">
                            <DataTrigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <ColorAnimation
                                            AutoReverse="True"
                                            FillBehavior="Stop"
                                            RepeatBehavior="5x"
                                            Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
                                            To="Yellow"
                                            Duration="0:0:0.5" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.EnterActions>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Border.Style>
            <TextBlock
                MinWidth="200"
                Background="White"
                FontSize="24"
                Text="{Binding Value, NotifyOnTargetUpdated=True}"
                TextAlignment="Center" />
        </Border>
        <Button Command="{Binding Path=SetValueCommand}" Content="Update Value" />
    </StackPanel>
</Window>

MainWindowVm.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using AgentOctal.WpfLib;
using AgentOctal.WpfLib.Commands;

namespace BindingHelp
{
    class MainWindowVm : ViewModel
    {
        private string _value;
        public string Value
        {
            get { return _value; }
            set
            {
                if (SetValue(ref _value, value))
                {
                    ShouldAnimate = true;
                }
            }
        }

        private bool _shouldAnimate = false;
        public bool ShouldAnimate
        {
            get { return _shouldAnimate; }
            set { SetValue(ref _shouldAnimate, value); }
        }


        private ICommand _setValueCommand;
        public ICommand SetValueCommand
        {
            get
            {
                return _setValueCommand ?? (_setValueCommand = new SimpleCommand((obj) =>
                {
                    Value = "This is a test!";
                }));
            }
        }    
    }
}