[UWP] Animating elements when they become Visible

Aria Rad 51 Reputation points
2022-11-23T20:25:00.523+00:00

Hello,

I would like to have a page element (typically a stackpanel or a grid) be animated when it is made visible. These elements can be toggled visible or collapsed with a button and this can be done repeatedly. The problem is that while using a ContentThemeTransition or EntranceThemeTransition gives a decent animation, these transitions only play once where I want them to play every time the element becomes visible.

So I thought about making a custom animation that affects the Y offset and the opacity. But I don't know how I can make it so that every time the element's Visibility changes to Visible the animation starts playing. I tried to Trigger the animation when the element becomes Visible, but couldn't figure out how to do it (with StateTriggers). Is this how it should be done and if so how?
Is it possible to have this behaviour be handled by the XAML code entirely? Also, is it possible to make said code into its own style so we can put it into a resource dictionary for the app for re-use?
I've been messing around in Blend with some sample code:

<StackPanel Orientation="Vertical">  
          
        <Button x:Name="test" Click="test_Click" Content="Animate" Margin="24"/>  
        <StackPanel Orientation="Vertical" x:Name="targetstackpanel"   
                                Margin="24,0,0,0"  
                                Visibility="Visible" RenderTransformOrigin="0.5,0.5">  
            <StackPanel.RenderTransform>  
                <CompositeTransform/>  
            </StackPanel.RenderTransform>  
            <VisualStateManager.VisualStateGroups>  
                <VisualStateGroup x:Name="VisualStateGroup">  
                    <VisualStateGroup.Transitions>  
                        <VisualTransition GeneratedDuration="00:00:00" To="Appearing">  
                            <VisualTransition.GeneratedEasingFunction>  
                                <ExponentialEase EasingMode="EaseOut"/>  
                            </VisualTransition.GeneratedEasingFunction>  
                            <Storyboard>  
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="targetstackpanel" Storyboard.TargetProperty="(UIElement.Opacity)">  
                                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>  
                                    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1"/>  
                                </DoubleAnimationUsingKeyFrames>  
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="targetstackpanel" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">  
                                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-25"/>  
                                    <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="0"/>  
                                </DoubleAnimationUsingKeyFrames>  
                            </Storyboard>  
                        </VisualTransition>  
                    </VisualStateGroup.Transitions>  
                    <VisualState x:Name="CollapsedPanel"/>  
                    <VisualState x:Name="Appearing"></VisualState>  
                </VisualStateGroup>  
            </VisualStateManager.VisualStateGroups>  
  
            <StackPanel Orientation="Vertical" Margin="0,6">  
                <TextBlock Style="{StaticResource BodyTextBlockStyle}"  
                                       FontWeight="Bold" TextWrapping="Wrap">  
                    Header1  
                </TextBlock>  
                <TextBlock Style="{StaticResource BodyTextBlockStyle}"  
                                       TextWrapping="Wrap" Margin="12,0,0,0">  
                    - Lorem ipsum dolor sit amet, consectetur adipiscing elit.  
                    <LineBreak/>- Phasellus ultricies turpis  
                    <LineBreak/>- sit amet turpis accumsan, vel placerat  
                    <LineBreak/>- nisi elementum.  
                    <LineBreak/>- Quisque aliquam ante non lorem varius,   
                    at porta urna bibendum.   
                    <LineBreak/>- Vestibulum lacinia vulputate nunc vel rutrum.   
                    Aliquam ac lobortis dolor. Donec blandit ante sed sem   
                    varius posuere.  
                    <LineBreak/>- Aliquam fringilla mauris condimentum,   
                    consequat lectus id, elementum lacus.  
                    <LineBreak/>- Duis mollis fermentum laoreet.  
                    <LineBreak/>- Nam in leo orci.  
                </TextBlock>  
            </StackPanel>  
            <StackPanel Orientation="Vertical" Margin="0,6">  
                <TextBlock Style="{StaticResource BodyTextBlockStyle}"  
                                       FontWeight="Bold" TextWrapping="Wrap">  
                    Header2  
                </TextBlock>  
                <TextBlock Style="{StaticResource BodyTextBlockStyle}"  
                                       TextWrapping="Wrap" Margin="12,0,0,0">  
                                - Vivamus nisl sem,  
                                <LineBreak/>- ornare eget sodales quis  
                </TextBlock>  
            </StackPanel>  
            <Button Content="Some button"   
                                x:Name="btn" HorizontalAlignment="Stretch"/>  
        </StackPanel>  
  
    </StackPanel>  

The code-behind looks something like this:

private void test_Click(object sender, RoutedEventArgs e)  
        {  
            if (targetstackpanel.Visibility == Windows.UI.Xaml.Visibility.Collapsed)  
            {  
                targetstackpanel.Visibility = Windows.UI.Xaml.Visibility.Visible;  
            }  
            else  
            {  
                targetstackpanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;  
            }  
        }  
Universal Windows Platform (UWP)
{count} votes

Accepted answer
  1. Roy Li - MSFT 31,766 Reputation points Microsoft Vendor
    2022-11-24T10:09:40.093+00:00

    Hello,

    Welcome to Microsoft Q&A!

    You could try to use DataTriggerBehavior and GoToStateAction from XAML Behaviors SDK to get your target.

    Here is a simple sample that I made

        <Page.Resources>  
            <Storyboard x:Name="myAnimation">  
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="targetstackpanel" Storyboard.TargetProperty="(UIElement.Opacity)">  
                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>  
                    <EasingDoubleKeyFrame KeyTime="00:00:05" Value="1"/>  
                </DoubleAnimationUsingKeyFrames>  
                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="targetstackpanel" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">  
                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-25"/>  
                    <EasingDoubleKeyFrame KeyTime="00:00:05" Value="0"/>  
                </DoubleAnimationUsingKeyFrames>  
            </Storyboard>  
        </Page.Resources>  
      
        <Grid x:Name="RootGrid">  
            <Button Content="Click" Click="Button_Click"/>  
              
            <StackPanel x:Name="targetstackpanel" Background="Aqua" Width="200" Visibility="Collapsed"   Height="200" Margin="24,0,0,0">  
                <StackPanel.RenderTransform>  
                    <CompositeTransform />  
                </StackPanel.RenderTransform>  
                <TextBlock Text="This is a Text" Foreground="BlueViolet"/>  
            </StackPanel>  
            <Interactivity:Interaction.Behaviors>  
                <Core:DataTriggerBehavior Binding="{Binding Visibility, ElementName=targetstackpanel}" Value="Visible">  
                    <Core:CallMethodAction TargetObject="{Binding}" MethodName="StartAnimation"/>  
                </Core:DataTriggerBehavior>  
            </Interactivity:Interaction.Behaviors>  
        </Grid>  
    

    Code-behind:

    public MainPage()  
            {  
                this.InitializeComponent();  
                this.DataContext = this;  
            }  
      
            private void Button_Click(object sender, RoutedEventArgs e)  
            {  
                targetstackpanel.Visibility = Visibility.Visible;  
                 
            }  
      
            public void StartAnimation()  
            {  
                myAnimation.Begin();  
            }  
    

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Aria Rad 51 Reputation points
    2022-11-24T21:59:55.93+00:00

    Thanks a lot! That works.

    0 comments No comments