Search code examples
wpfxamllayoutstoryboardexpander

stackpanel triggers and storyboard


When setting my stackpanel triggers for my expander content I begin a story board animation but how can I use the story board animation the same way in reverse?

<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="1.2" Duration="0:0:0.45" Storyboard.TargetName="content" Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleX)"/>
</Storyboard>
</BeginStoryboard>

This will slowly slide out the expander contents but it snaps back like an original expander? I want to set it so it will also slowly come back in aswell as out?

For instance if I add/use on the DoubleAnimation:

AutoReverse="True"

When I click the expander it will open then close rather than open on click close on click? So not to sure how I can achieve my goal.

EDIT:

    <StackPanel Orientation="Horizontal" >
            <StackPanel.Triggers>
                <EventTrigger RoutedEvent="Expander.Expanded" SourceName="expander1">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation From="0" To="1.2" Duration="0:0:0.45" Storyboard.TargetName="content" Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleX)"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </StackPanel.Triggers>
            <Expander ExpandDirection="Right" Name="expander1" OpacityMask="#6C806969" Background="#FF807171">
                <Expander.Header>
                    <TextBlock Text="  FORUMS" Foreground="#FFFCB798" FontSize="41" FontStretch="UltraExpanded">                      
                <TextBlock.LayoutTransform>
                    <RotateTransform Angle="90"></RotateTransform>
                </TextBlock.LayoutTransform>
                        </TextBlock>
                </Expander.Header> 
                <Grid x:Name="content" Background="#FF807171" Width="378">
                    <Grid.LayoutTransform>
                        <ScaleTransform ScaleX="0" ScaleY="1"/>
                    </Grid.LayoutTransform>
                </Grid>
            </Expander>

Solution

  • You need two Storyboards.

    One does the slide out the other does the slide in.

    Inside your Expander control you will need a ToggleButton. When this ToggleButton is Checked, fire the slide out animation, when it is Unchecked, fire the slide in animation.

    UPDATE

    I personally prefere to do this types of animations inside the style of the control, so you don't need to duplicate the code and they can be easily shared.

    What I have done here is, I created a new Expander style based on its default style.

    Inside the style, I set its ExpandSite to be always Visible and removed the code that made ExpandSite Visible when IsExpanded is set to True. Also I created two storyboards that handle the slide out and slide in animations.

    In the slide out animation (i.e. ExpandAnimation), I set the Visibility of ExpandSite to Visible at the start and then animate its ScaleX; while in the slide in animation (i.e. CollapseAnimation), I animate its ScaleX first and set the Visibility to be Collapsed at the very end.

    I have attached the full code for your reference.

    <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
        x:Class="animationtest.MainWindow"
        x:Name="Window"
        Title="MainWindow"
        Width="640" Height="480">
        <Window.Resources>
            <Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border Padding="{TemplateBinding Padding}">
                                <Grid Background="Transparent" SnapsToDevicePixels="False">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="19"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>
                                    <Grid>
                                        <Grid.LayoutTransform>
                                            <TransformGroup>
                                                <TransformGroup.Children>
                                                    <TransformCollection>
                                                        <RotateTransform Angle="-90"/>
                                                    </TransformCollection>
                                                </TransformGroup.Children>
                                            </TransformGroup>
                                        </Grid.LayoutTransform>
                                        <Ellipse x:Name="circle" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                        <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="#666" StrokeThickness="2" VerticalAlignment="Center"/>
                                    </Grid>
                                    <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked" Value="true">
                                    <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                    <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border Padding="{TemplateBinding Padding}">
                                <Grid Background="Transparent" SnapsToDevicePixels="False">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="19"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid>
                                        <Grid.LayoutTransform>
                                            <TransformGroup>
                                                <TransformGroup.Children>
                                                    <TransformCollection>
                                                        <RotateTransform Angle="180"/>
                                                    </TransformCollection>
                                                </TransformGroup.Children>
                                            </TransformGroup>
                                        </Grid.LayoutTransform>
                                        <Ellipse x:Name="circle" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                        <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="#666" StrokeThickness="2" VerticalAlignment="Center"/>
                                    </Grid>
                                    <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked" Value="true">
                                    <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                    <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border Padding="{TemplateBinding Padding}">
                                <Grid Background="Transparent" SnapsToDevicePixels="False">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="19"/>
                                        <RowDefinition Height="*"/>
                                    </Grid.RowDefinitions>
                                    <Grid>
                                        <Grid.LayoutTransform>
                                            <TransformGroup>
                                                <TransformGroup.Children>
                                                    <TransformCollection>
                                                        <RotateTransform Angle="90"/>
                                                    </TransformCollection>
                                                </TransformGroup.Children>
                                            </TransformGroup>
                                        </Grid.LayoutTransform>
                                        <Ellipse x:Name="circle" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                        <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="#666" StrokeThickness="2" VerticalAlignment="Center"/>
                                    </Grid>
                                    <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" Grid.Row="1" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Top"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked" Value="true">
                                    <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                    <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="ExpanderHeaderFocusVisual">
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border>
                                <Rectangle Margin="0" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border Padding="{TemplateBinding Padding}">
                                <Grid Background="Transparent" SnapsToDevicePixels="False">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="19"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Ellipse x:Name="circle" HorizontalAlignment="Center" Height="19" Stroke="DarkGray" VerticalAlignment="Center" Width="19"/>
                                    <Path x:Name="arrow" Data="M 1,1.5 L 4.5,5 L 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="false" Stroke="#666" StrokeThickness="2" VerticalAlignment="Center"/>
                                    <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked" Value="true">
                                    <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                                    <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                    <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="ExpanderStyle1" TargetType="{x:Type Expander}">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Expander}">
                            <ControlTemplate.Resources>
                                <Storyboard x:Key="ExpandAnimation">
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="ExpandSite">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/>
                                    </DoubleAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ExpandSite">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                                <Storyboard x:Key="CollapseAnimation">
                                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="ExpandSite">
                                        <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
                                    </DoubleAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ExpandSite">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0.4" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </ControlTemplate.Resources>
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
                                <DockPanel>
                                    <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                    <ContentPresenter x:Name="ExpandSite" DockPanel.Dock="Bottom" Focusable="false" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RenderTransformOrigin="0,0.5">
                                        <ContentPresenter.RenderTransform>
                                            <TransformGroup>
                                                <ScaleTransform ScaleX="0"/>
                                                <SkewTransform/>
                                                <RotateTransform/>
                                                <TranslateTransform/>
                                            </TransformGroup>
                                        </ContentPresenter.RenderTransform>
                                    </ContentPresenter>
                                </DockPanel>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsExpanded" Value="True">
                                    <Trigger.EnterActions>
                                        <BeginStoryboard
                                x:Name="ExpandAnimation_BeginStoryboard" Storyboard="{StaticResource ExpandAnimation}"/>
                                    </Trigger.EnterActions>
                                    <Trigger.ExitActions>
                                        <BeginStoryboard
                                x:Name="CollapseAnimation_BeginStoryboard" Storyboard="{StaticResource CollapseAnimation}"/>
                                    </Trigger.ExitActions>
                                </Trigger>
                                <Trigger Property="ExpandDirection" Value="Right">
                                    <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                                    <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                                    <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
                                </Trigger>
                                <Trigger Property="ExpandDirection" Value="Up">
                                    <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                                    <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                                    <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
                                </Trigger>
                                <Trigger Property="ExpandDirection" Value="Left">
                                    <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                                    <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                                    <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
                                </Trigger>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
    
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Expander Header="Expander" ExpandDirection="Right" Style="{DynamicResource ExpanderStyle1}" IsExpanded="True">
                <Expander.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="  TEST" Foreground="#FFFCB798" FontSize="41" FontStretch="UltraExpanded">                       
                            <TextBlock.LayoutTransform> 
                                <RotateTransform Angle="90"/> 
                            </TextBlock.LayoutTransform> 
                        </TextBlock>
                    </DataTemplate>
                </Expander.HeaderTemplate>
                <StackPanel OpacityMask="#6C806969" Background="#FF807171">
                    <TextBox TextWrapping="Wrap" Text="TextBlock" Margin="12" Width="240"/>
                    <TextBox TextWrapping="Wrap" Text="TextBlock" Margin="12" Width="240"/>
                    <Button Content="Button" Width="80" Margin="12"/>
                </StackPanel>
            </Expander>
        </Grid>
    </Window>
    

    Hope this helps!