samc
Topic Author
Posts: 43
Joined: 21 Aug 2019, 19:22

StoryboradCompletedTrigger woes

27 Sep 2022, 02:56

I'm trying to implement a "ping" icon for my map (ie, something that does a little pulse to draw your attention).

I have a data template for my PingIcon. I made some visual states: "Pinged" and "Hidden". I made a storyboard that does the ping animation that is triggered from the "Pinged" stated.

The problem that I was running into is that if I am in the "Pinged" state, and then hit my data trigger, it doesn't re-play the "ping" animation storyboard in my "Pinged" state. I'm assuming there is some sort of optimization that prevents you transition back to the same state? It would make sense. But maybe there is a way to do this? open to ideas here.

So, I decided to add a new state: "Visible" which didn't have any storyboard; it was just when the ping icon is visible.. I added a StoryboardCompletedTrigger for the storyboard that is triggered for the "ping" state. My idea was that I would add a "GoToStateAction" here and transition to the "Visible" state so that the next time the "ping" data trigger happened, it would be transition back to the "Pinged" state and the animation would play again.

Unfortunately, as far as I can tell, the StoryboardCompletedTrigger isn't working on the data template. While debugging, I switched the GoToStateAction with just a ChangePropertyAction that should have changed the visibility of the control -- but even that didn't do anything, so I'm skeptical that the trigger is every happening. I also set breakpoints in the StoryboardCompletedTrigger class, and I don't see that "OnStoryboardChanged" is being called when my storyboard finishes.

I was going to attempt to debug this more, but I'm not sure what the best steps would be.. Any suggestions? Is there a better way to do this entirely?

thanks,
sam
 
samc
Topic Author
Posts: 43
Joined: 21 Aug 2019, 19:22

Re: StoryboradCompletedTrigger woes

27 Sep 2022, 03:10

Forgot to post this. Here is my basic setup:
<DataTemplate x:Key="MapIcon_Ping_Template">
    <DataTemplate.Resources>
        <Storyboard x:Key="PingAnimationStoryBoard">
            <!--  story board is here -->
        </Storyboard>
    </DataTemplate.Resources>
    <Canvas x:Name="Root" RenderTransform="{Binding Transform}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="PingInitiatedStates">
                <VisualState x:Name="PingedState" Storyboard="{StaticResource PingAnimationStoryBoard}">
                </VisualState>
                <VisualState x:Name="PingVisibleState">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="IntroPulses">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="PingHiddenState">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="IntroPulses">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        
        <Grid x:Name="PingStateTriggers">
            <b:Interaction.Triggers>
                <b:DataTrigger Binding="{Binding Disabled}" Comparison="Equal" Value="True">
                    <b:ChangePropertyAction x:Name="MapIcon_Ping_Template_Disabled" TargetName="Root" PropertyName="Visibility" Value="Collapsed"/>
                    <b:GoToStateAction x:Name="MapIcon_Ping_IntroPulse_Disabled" StateName="PingHiddenState" TargetName="Root"/>
                </b:DataTrigger>

                <b:DataTrigger Binding="{Binding Disabled}" Comparison="Equal" Value="False">
                    <b:ChangePropertyAction x:Name="MapIcon_Ping_Template_Enabled" TargetName="Root" PropertyName="Visibility" Value="Visible"/>
                    <b:GoToStateAction x:Name="MapIcon_Ping_IntroPulse_Enabled" StateName="PingedState" TargetName="Root"/>
                </b:DataTrigger>

                <b:StoryboardCompletedTrigger Storyboard="{StaticResource PingAnimationStoryBoard}">
                    <b:GoToStateAction x:Name="MapIcon_Ping_IntroPulse_Completed" StateName="PingVisibleState" TargetName="Root"/>
                    <!-- debug testing: -->
                    <!-- <b:ChangePropertyAction x:Name="MapIcon_Ping_IntroPulse_Completed" TargetName="Root" PropertyName="Visibility" Value="{x:Static Visibility.Collapsed}"/> -->
                </b:StoryboardCompletedTrigger>

                <noesis:DataEventTrigger Source="{Binding}" EventName="PingedEvent">
                    <b:ChangePropertyAction x:Name="MapIcon_PingEvent_Template_Enabled" TargetName="Root" PropertyName="Visibility" Value="Visible"/>
                    <b:GoToStateAction x:Name="MapIcon_PingEvent_IntroPulse_Enabled" StateName="PingedState" TargetName="Root"/>
                </noesis:DataEventTrigger>
            </b:Interaction.Triggers>
        </Grid>
    ...
    
 
User avatar
sfernandez
Site Admin
Posts: 2664
Joined: 22 Dec 2011, 19:20

Re: StoryboradCompletedTrigger woes

27 Sep 2022, 18:16

Hi Sam, I'll investigate why the StoryboardCompletedTrigger doesn't work in that scenario, but in the meantime it would be enough to just start the "ping" animation when you fire the PingedEvent from your view model (if I understood correctly what you try to do):
<noesis:DataEventTrigger Source="{Binding}" EventName="PingedEvent">
  <b:ChangePropertyAction x:Name="MapIcon_PingEvent_Template_Enabled" TargetName="Root" PropertyName="Visibility" Value="Visible"/>
  <b:ControlStoryboardAction x:Name="MapIcon_PingEvent_IntroPulse_Enabled" Storyboard="{StaticResource PingAnimationStoryBoard}"/>
</noesis:DataEventTrigger>
<b:DataTrigger Binding="{Binding Disabled}" Value="True">
  <b:ChangePropertyAction x:Name="MapIcon_PingEvent_Template_Disabled" TargetName="Root" PropertyName="Visibility" Value="Hidden"/>
</b:DataTrigger>
So everytime the event is fired, the animation is started, no need to change any visual state.
 
samc
Topic Author
Posts: 43
Joined: 21 Aug 2019, 19:22

Re: StoryboradCompletedTrigger woes

27 Sep 2022, 20:13

ControlStoryboardAction worked! thank you!

sam

Who is online

Users browsing this forum: No registered users and 1 guest