代码之家  ›  专栏  ›  技术社区  ›  Oskar

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

  •  3
  • Oskar  · 技术社区  · 15 年前

    为这个小问题道歉,我是WPF新手,一直在寻找能描述我想要的东西的博客…

    我有一个标签绑定到一个属性,并在屏幕上进行了很好的更新,现在我想要一个小动画,每当更新值时,它就会闪烁标签的背景色。理想情况下,我想要一个纯XAML解决方案

    我看过DataTriggers,但它们似乎需要一个相等条件来保持,并且EventTriggers似乎不可能附加到任何与数据显示有关的事件上。

    谢谢 奥斯卡

    3 回复  |  直到 13 年前
        1
  •  2
  •   serge_gubenko    15 年前

    请检查下面的代码是否适用于您。对标签内容属性的任何更改都将设置动画。它是通过使用触发器和值转换器类来完成的,这个类将内容值转换为“真”或“假”,并设置触发器对这两个值做出反应。cnverter附加到标签的tag属性,该属性被弯折为数据上下文的name属性。另外,我还添加了一些动画到鼠标输入和离开事件中,这些事件非常简单,只使用XAML中的RouteRevents完成。

    转换器:

    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>
    

    希望这有帮助,问候

        2
  •  7
  •   Luk    13 年前

    你不应该使用事件触发器吗? 你需要设置 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>
    
        3
  •  2
  •   Ray Burns    15 年前

    我喜欢谢尔盖·古本科的回答,但我想我应该提一下我有时会用到的另一种技巧。Serge的答案更接近您的“纯XAML”理想,因为它只有一个转换器,但是这个答案的代码更少,而且可读性更高。这里是:

    将propertyChangedCallback添加到“name”属性中,然后从中启动情节提要:

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

    如果在窗口首次加载时不希望闪烁,可以添加标志:

    ...
      PropertyChangedCallback = (obj, e) =>
      {
        if(_initialized)
          storyBoard.Begin();
      }
    ...
    
    protected override void OnInitialized(...)
    {
      _initialized = true;
    }