开发者

How do I trigger an animation when a label changes value in WPF?

Apologies for this trivial question, I'm new to WPF and keep finding blogs that almost describe what I want...

I have a Label that is bound to a property and updating nicely on screen, and now I'd like a small animation that flashes the background colour of the label whenever the value is updated. Ideally I'd like a pure xaml solution

I've looked at DataTriggers but they seem to require an equality condition to hold, and EventTriggers seem to not be possible to attached to any ev开发者_如何学运维ents to do with the display of data

thanks Oskar


Shouldn't you use an event trigger? You need to set NotifyOnTargetUpdated=True in the binding, but this works in my code.

<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>


please check if code below would work for you. Any change for Content property of the label is animated. It's done using triggers and value converter class which does the small trick converting content value to either "True" or "False" and triggers are set up to react on those 2 values. Cnverter is attached to the Tag property of the label which is bent to the Name property of data context. Also I've added some animation to mouse enter and leave events which are pretty straightforward and done only using RouterEvents in xaml.

converter:

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;
    }
}

data context initialization:

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>

hope this helps, regards


I liked serge_gubenko's answer but thought I should mention another technique I sometimes use. Serge's answer is closer to your "pure XAML" ideal because it only has a converter, but this answer has less code and may be more readable. Here it is:

Add a PropertyChangedCallback to your "Name" property and start the storyboard from there:

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

If you don't want a flash when the window first loads, you can add a flag:

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

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜