A question about fades in XAML

Richard Hille 1 Reputation point
2020-06-23T20:39:32.417+00:00

Hello all

I have a question about XAML. I looked at a lot of examples these last few days trying to figure something out without any success... What I am trying to achieve is this: I created a style for some buttons I will be using. I would like those buttons to fade into view when I set their property to Visible, and fade out when I set the property to Collapsed. Everything works perfectly for the Fade In but not at all for the Fade Out. Could somebody point me in the right direction please?

Here is the XAML code:

<Style x:Key = "RegularBtnWithFadeStyle"
        TargetType = "{x:Type Button}">

    <Setter Property = "BorderBrush"
            Value = "White"/>
    <Setter Property = "BorderThickness"
            Value = "2"/>
    <Setter Property = "Margin"
            Value = "0, 1, 0, 1"/>
    <Setter Property = "IsCancel"
            Value = "False"/>
    <Setter Property = "Visibility" 
            Value = "Collapsed" />
    <Setter Property = "Template">
        <Setter.Value>
            <ControlTemplate TargetType = "Button">
                <Grid Width = "{TemplateBinding Width}" 
                        Height = "{TemplateBinding Height}" 
                        ClipToBounds = "True">
                    <Rectangle x:Name = "outerRectangle" 
                                HorizontalAlignment = "Stretch" 
                                VerticalAlignment = "Stretch" 
                                Stroke = "{StaticResource SS_BtnForegroundColorWhenIdle}" 
                                RadiusX = "5" 
                                RadiusY = "5" 
                                StrokeThickness = "1" 
                                Fill = "{StaticResource SS_BtnBackgroundColorWhenIdle}"/>
                    <DockPanel Name = "myContentPresenterDockPanel">
                        <ContentPresenter x:Name = "myContentPresenter" 
                                        Content = "{TemplateBinding Content}"
                                        HorizontalAlignment = "Center"
                                        VerticalAlignment = "Center"
                                        TextBlock.FontFamily = "Segoe UI"
                                        TextBlock.FontWeight = "SemiBold"
                                        TextBlock.Foreground = "{StaticResource SS_BtnForegroundColorWhenIdle}"
                                        Margin = "{TemplateBinding Padding}"/>
                    </DockPanel>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property = "IsMouseOver" 
                            Value = "True">
                        <Setter TargetName = "outerRectangle"  
                                Property = "Fill"
                                Value = "{StaticResource SS_BtnBackgroundColorWhenMouseOver}"/>
                        <Setter Property = "TextBlock.Foreground"
                                TargetName = "myContentPresenter"
                                Value = "{StaticResource SS_BtnForegroundColorWhenMouseOver}"/>
                    </Trigger>
                    <Trigger Property = "IsPressed" 
                            Value = "True">
                        <Setter TargetName = "outerRectangle"
                                Property = "Fill"
                                Value = "{StaticResource SS_BtnBackgroundColorWhenPressed}"/>
                        <Setter Property = "TextBlock.Foreground"
                                TargetName = "myContentPresenter"
                                Value = "{StaticResource SS_BtnForegroundColorWhenPressed}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Resources>
        <Storyboard x:Key = "FadeIn">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Opacity)"
                                        Storyboard.TargetName = "{x:Null}"
                                        BeginTime = "0:0:0">
                <EasingDoubleKeyFrame KeyTime = "0:0:0"
                                    Value = "0"/>
                <EasingDoubleKeyFrame KeyTime = "0:0:0.5"
                                    Value = "0"/>
                <EasingDoubleKeyFrame KeyTime = "0:0:1"
                                    Value = "1"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Visibility)"
                                        Storyboard.TargetName = "{x:Null}"
                                        BeginTime = "0:0:0">
                <DiscreteObjectKeyFrame KeyTime = "0:0:0.0"
                                    Value = "{x:Static Visibility.Visible}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key = "FadeOut">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Opacity)"
                                        Storyboard.TargetName = "{x:Null}"
                                        BeginTime = "0:0:0">
                <EasingDoubleKeyFrame KeyTime = "0:0:0"
                                    Value = "1"/>
                <EasingDoubleKeyFrame KeyTime = "0:0:0.5"
                                    Value = "1"/>
                <EasingDoubleKeyFrame KeyTime = "0:0:3"
                                    Value = "0"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Visibility)"
                                        Storyboard.TargetName = "{x:Null}"
                                        BeginTime = "0:0:0">
                <DiscreteObjectKeyFrame KeyTime = "0:0:3"
                                    Value = "{x:Static Visibility.Collapsed}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>
    </Style.Resources>
    <Style.Triggers>
        <Trigger Property = "IsVisible" 
            Value = "True">
            <Trigger.EnterActions>
                <BeginStoryboard Storyboard = "{StaticResource FadeIn}"/>
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard Storyboard = "{StaticResource FadeOut}"/>
            </Trigger.ExitActions>
        </Trigger>
    </Style.Triggers>
</Style>

I have set the duration of the fade to 3 seconds just for now, in order to really see the animation. Here is the code for the button itself:

<Button x:Name = "EnglishLanguageBtn"
       Click = "EnglishLanguageBtn_Click"
       Content = "English"
       FontFamily = "Segoe UI"
       FontSize = "16"
       FontWeight = "Semibold"
       Grid.Column = "0"
       Grid.Row = "1"
       Height = "30"
       HorizontalAlignment = "Left"
       IsCancel = "False"
       IsTabStop = "False"
       Margin = "435, 185, 0, 0"
       Padding = "0, 0, 0, 3"
       Style = "{DynamicResource RegularBtnWithFadeStyle}"
       VerticalAlignment = "Top"
       Visibility = "Collapsed"
       Width = "105"/>

Like I said at the beginning of the post, I was thinking of simply calling Visible or Collapsed to start the entry or exit animation. What am I missing?

Many thanks

Rick

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,686 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. DaisyTian-1203 11,616 Reputation points
    2020-06-24T07:10:43.77+00:00

    The problem is that after your animation completes your control still has Visibility=Visible, so it cannot be entered again. You need set AutoReverse="True" for your FadeIn and FadeOut Storyboard.

      <Storyboard x:Key = "FadeIn">
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Opacity)"
                                             Storyboard.TargetName = "{x:Null}"
                                             BeginTime = "0:0:0" AutoReverse="True">
                                <EasingDoubleKeyFrame KeyTime = "0:0:0"
                                         Value = "0"/>
                                <EasingDoubleKeyFrame KeyTime = "0:0:0.5"
                                         Value = "0"/>
                                <EasingDoubleKeyFrame KeyTime = "0:0:1"
                                         Value = "1"/>
                            </DoubleAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Visibility)"
                                             Storyboard.TargetName = "{x:Null}"
                                             BeginTime = "0:0:0" AutoReverse="True" >
                                <DiscreteObjectKeyFrame KeyTime = "0:0:0.0"
                                         Value = "{x:Static Visibility.Visible}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                        <Storyboard x:Key = "FadeOut">
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Opacity)"
                                             Storyboard.TargetName = "{x:Null}"
                                             BeginTime = "0:0:0" AutoReverse="True">
                                <EasingDoubleKeyFrame KeyTime = "0:0:0"
                                         Value = "1"/>
                                <EasingDoubleKeyFrame KeyTime = "0:0:0.5"
                                         Value = "1"/>
                                <EasingDoubleKeyFrame KeyTime = "0:0:3"
                                         Value = "0"/>
                            </DoubleAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty = "(UIElement.Visibility)"
                                             Storyboard.TargetName = "{x:Null}"
                                             BeginTime = "0:0:0" AutoReverse="True" >
                                <DiscreteObjectKeyFrame KeyTime = "0:0:3"
                                         Value = "{x:Static Visibility.Collapsed}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
    
    0 comments No comments

  2. Richard Hille 1 Reputation point
    2020-06-24T14:25:46.267+00:00

    @DaisyTian-MSFT

    Thank you for your answer. Unfortunately, this modification does not do exactly what I want. The way I understand the AutoReverse property is that the Storyboard will play in reverse once it is completed. I tried it, and sure enough, the button appeared and then, disappeared. Since it is a button that the user needs to click, I want it to stay visible until the user clicks on it and then, when I call "Collapsed" in code, the button fades out.

    Unless I misunderstand the solution you suggested.

    Thanks again for your help.

    Rick

    0 comments No comments

  3. gekka 6,931 Reputation points MVP
    2020-06-25T00:55:04.747+00:00

    Visibility property interferes with IsVisible property, so the trigger does not work as intended.

    Your code requires IsVisible to be non-true for ExitActions to be triggered, so of course the button is not displayed and no animation will be shown at that point.

    <DockPanel TextElement.FontSize="16">
        <DockPanel.Resources>
            <Style x:Key="RegularBtnWithFadeStyle" TargetType="{x:Type Button}">
                <Setter Property="Visibility" Value="Collapsed" />
                <Setter Property="Opacity" Value="0" />
    
                <Style.Resources>
                    <Storyboard x:Key="FadeIn">
                        <DoubleAnimationUsingKeyFrames
                            Storyboard.TargetProperty="(UIElement.Opacity)" 
                            Storyboard.TargetName="{x:Null}"
                            BeginTime="0:0:0">
    
                            <EasingDoubleKeyFrame KeyTime="0:0:0.5" />
                            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
                        </DoubleAnimationUsingKeyFrames>
    
                        <ObjectAnimationUsingKeyFrames
                            Storyboard.TargetProperty="(UIElement.Visibility)" 
                            Storyboard.TargetName="{x:Null}"
                            BeginTime="0:0:0">
    
                            <DiscreteObjectKeyFrame KeyTime="0:0:0.0" Value="{x:Static Visibility.Visible}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
    
                    <Storyboard x:Key="FadeOut">
                        <DoubleAnimationUsingKeyFrames
                            Storyboard.TargetProperty="(UIElement.Opacity)"
                            Storyboard.TargetName="{x:Null}"
                            BeginTime="0:0:0">
    
                            <EasingDoubleKeyFrame KeyTime="0:0:0.5" />
                            <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
                        </DoubleAnimationUsingKeyFrames>
    
                        <ObjectAnimationUsingKeyFrames 
                            Storyboard.TargetProperty="(UIElement.Visibility)"
                            Storyboard.TargetName="{x:Null}"
                            BeginTime="0:0:0">
    
                            <DiscreteObjectKeyFrame KeyTime="0:0:3" Value="{x:Static Visibility.Collapsed}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </Style.Resources>
    
                <Style.Triggers>
                    <!-- Visibility property interferes with IsVisible property, so the trigger does not work as intended -->
                    <Trigger Property="Tag" Value="{x:Static Visibility.Visible}" >
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource FadeIn}"/>
                        </Trigger.EnterActions>
    
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource FadeOut}"/>
                        </Trigger.ExitActions>
                    </Trigger>
                </Style.Triggers>
            </Style>
    
            <BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />
        </DockPanel.Resources>
    
        <CheckBox x:Name="chk" IsChecked="False" Content="Visible" DockPanel.Dock="Bottom" Margin="20"/>
    
        <Button Style="{StaticResource RegularBtnWithFadeStyle}"  
                Tag="{Binding ElementName=chk,Path=IsChecked,Converter={StaticResource booleanToVisibilityConverter}}"
                Content="English" />
    </DockPanel>
    
    0 comments No comments