.net – How to combine DataTrigger and EventTrigger

datatriggernettriggerswpfxaml

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger?

I think I need to combine an EventTrigger and a DataTrigger to achieve what I'm after:

  • when an item appears in my ListBox, it should flash for a few moments
  • if the item is 'Critical' then it should remain highlighted

Currently I have a DataTemplate that looks like this:

<DataTemplate DataType="{x:Type Notifications:NotificationViewModel}">
    <Grid HorizontalAlignment="Stretch">
        <Border Name="Background" CornerRadius="8" Background="#80c0c0c0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
        <Border Name="Highlight"  CornerRadius="8" Background="Red"       HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
        <!-- snip actual visual stuff -->
        <Grid.Triggers>
            <EventTrigger RoutedEvent="Grid.Loaded">
                <EventTrigger.Actions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation x:Name="LoadedAnimation" 
                                             Storyboard.TargetName="Highlight" 
                                             Storyboard.TargetProperty="Opacity" 
                                             From="0" To="1" 
                                             RepeatBehavior="5x" 
                                             Duration="0:00:0.2" 
                                             AutoReverse="True" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger.Actions>
            </EventTrigger>
        </Grid.Triggers>
    </Grid>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=IsCritical}" Value="True">
            <Setter TargetName="LoadedAnimation" Property="RepeatBehavior" Value="5.5x" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

The idea is that an EventTrigger animates the Highlight border's opacity between 0 and 1 and back again repeatedly when the item is first loaded, drawing the user's attention to it. The DataTrigger determines the number of times to animate. If the view model reports that the item IsCritical then the animation occurs 5.5 times (such that it ends at opacity 1), otherwise it occurs 5 times (ending at opacity 0.)

However the above XAML doesn't work because the DataTrigger's setter fails with:

Child with Name 'LoadedAnimation' not found in VisualTree.

Fair enough. So, shy of using a custom value converter or putting the animation count on the view model and binding to it, what are my options?

Best Answer

I would use a behavior instead of triggers in this case. You can write a behavior that attaches an event handler to the associated object's load event and then applies the animation. The behavior may expose some properties, I would expose an AnimationCount (int) property that tells the behavior how many time to repeat the animation on the element that it is associated with. You can then bind this property to the IsCritical property in the view model and use a value converter to convert false to 5 and true to 5.5

Hope this helps