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;
}
精彩评论