26
votes

I'm trying to execute an animation on a cell in a datagrid when the value of the datagrid cell changes.

The datagrid itself is bound to an ObservableCollection of plain old CLR objects. In this case lets say the objects are 'Person' objects with properties for 'Firstname', 'Lastname' and 'Age'. The 'Person' class implements the INotifyPropertyChanged interface and each property has the appropriate call to onPropertyChanged in it's setter.

This is all fine. In the datagrid definition I've set my DataTemplate for drawing each cell and attached a datatrigger too ... as follows:

<DataGridTemplateColumn Header="FirstName">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Border Name="templateBorder">
                <TextBlock Name="templateTextBlock" Text="{Binding Path=FirstName}" />
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=FirstName}" Value="Richard">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard AutoReverse="True">
                                <DoubleAnimation Storyboard.TargetName="templateTextBlock" Storyboard.TargetProperty="Opacity" To=".1" Duration="0:0:.5" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

When an object in my ObservableCollection is updated (I changed the FirstName value) the datagrid is updated fine. As per the example above, if I changed the value of FirstName to 'Richard' then the animation is executed fine too.

My problem is that I need to run my animation regardless of what the new value of Firstname is. I've crawled the web but some far only seem to find examples of firing the trigger against a known value e.g. fire trigger when FirstName is 'Richard' as I've demonstrated in my example.

My question is how do I fire the datatrigger regardless of the value of the updated property? So basically how do I fire the datatrigger whenever the FirstName property is updated for a given row in the datagrid.

Many thanks.

5
Why don't you try using Visual State Manager... See this post. stackoverflow.com/questions/15258199/…stromms

5 Answers

44
votes

Thanks to the pointers gained from the responses to this question I found the answer was to use an EventTrigger and the TargetUpdated RoutedEvent.

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

Beyond the EventTrigger, the only other thing that was required was to set 'NotifyOnTargetUpdated=True' when setting up the binding for the textblock.

Thanks.

2
votes

It looks like you need an EventTrigger "do X when an event occurs" instead of a DataTrigger.

Not tried this myself.. but it should be possible to raise your custom event FirstNameChanged and have the trigger-actions be executed in response to that.

1
votes
  <Storyboard x:Key="MessageStoryBoardEntry" FillBehavior="Stop">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                <EasingDoubleKeyFrame KeyTime="0:0:00.30" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:03" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="0:0:03.20" Value="1500"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <Storyboard x:Key="MessageStoryBoardExit" FillBehavior="Stop">

            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                <EasingDoubleKeyFrame KeyTime="0:0:0.001" Value="1500"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
0
votes

You could try setting the DataContext of the TextBlock to the FirstName property, and then use the DataContextChanged event.

Or you could use the PropertyChanged event and filter for the property you want.

Either way I think you're going to have to use an event.

0
votes

Could you hack something in with a value converter?

<DataTrigger Binding="{Binding Path=FirstName, Converter=FirstNameConverter}" Value="MakeItSo">

and

class FirstNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return "MakeItSo";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
...
    }
}

I guess it depends on whether WPF calls the converter on every property change, or whether it evaluates the value first. I've not tried it, it's just a thought...