Search code examples
c#wpfblendvisualstates

Transitioning "Visibility" in blend using visual states


So I have a loading control which if effectively a usercontrol that says "Loading" over the top of my main user control, preventing the user interacting with my program until it is loaded.

I would like to use visual states to transition the visibility of the "Loading" control to slowly fade to collapsed and stay collapsed for any other state within my program.

I currently have my loading control:

    <ContentControl x:Name="contentControl" Content="{StaticResource loadingAnimation}">
        <i:Interaction.Triggers>
            <ei:DataTrigger Value="false" Binding="{Binding IsLoadingAnimationVisible}">
                <ei:GoToStateAction StateName="Loaded"/>
            </ei:DataTrigger>
        </i:Interaction.Triggers>
    </ContentControl>

Where:

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateGroup">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:0.5" To="Collapsed">
                    <VisualTransition.GeneratedEasingFunction>
                        <CubicEase EasingMode="EaseInOut"/>
                    </VisualTransition.GeneratedEasingFunction>
                </VisualTransition>
                <VisualTransition GeneratedDuration="0:0:0.5" To="Expanded">
                    <VisualTransition.GeneratedEasingFunction>
                        <CubicEase EasingMode="EaseInOut"/>
                    </VisualTransition.GeneratedEasingFunction>
                </VisualTransition>
                <VisualTransition GeneratedDuration="0:0:0.5" To="Loaded">
                    <VisualTransition.GeneratedEasingFunction>
                        <CubicEase EasingMode="EaseInOut"/>
                    </VisualTransition.GeneratedEasingFunction>
                </VisualTransition>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="Expanded">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="contentControl">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Collapsed">
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="metaGrid">
                        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                    </DoubleAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="contentControl">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Loaded">
                <Storyboard>
                    <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.IsHitTestVisible)" Storyboard.TargetName="contentControl">
                        <DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
                    </BooleanAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="contentControl">
                        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

now the problem with this is that when I trigger the Expanded and Collapsed states the "Loading" contentControl becomes visible and then fades to collapsed over .5 seconds. How can I permanently set the loading control to collapsed once the Loaded state has been triggered?

EDIT

I am not sure this is the correct way to transition a visibility in blend (i.e. setting ishittestvisible = false and opacitiy = 0 but it was the only way I could think as setting visibility.collapsed didnt seem to transition when I tried it, it would snap to collapsed)


Solution

  • It sounds like you want to use the Timeline.BeginTime Property. Using this property, you can delay the start of the Visibility.Collapsed Animation. Ideally, you should set the Duration property on your DoubleAnimationUsingKeyFrames object too. Try this:

    <VisualState x:Name="Collapsed">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames Duration="0:0:5" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="metaGrid">
                <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="0:0:5" Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="contentControl">
                <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </VisualState>