Achieve “slide down” animation in WPF

后端 未结 3 1099
我在风中等你
我在风中等你 2020-12-15 09:33

I am attempting to create my own template for an Expander control. When the control is expanded, I want the content to slide down slowly.

The desired he

相关标签:
3条回答
  • 2020-12-15 09:42

    If you can use Interactions with FluidLayout (Blend 4 SDK) you are in luck, it's really useful for those fancy animation things.

    First set the content CP's Height to 0:

    <ContentPresenter Grid.Row="1"
        HorizontalAlignment="Stretch"
        x:Name="_expanderContent"
        Height="0"/>
    

    To animate this, the Height just needs to be animated to NaN in the VisualState that represents the expanded state (non-discrete animations would not let you use NaN):

    xmlns:is="http://schemas.microsoft.com/expression/2010/interactions"
    
    <Grid x:Name="MainGrid" Background="White">
        <VisualStateManager.CustomVisualStateManager>
            <is:ExtendedVisualStateManager/>
        </VisualStateManager.CustomVisualStateManager>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ExpansionStates" is:ExtendedVisualStateManager.UseFluidLayout="True">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0:0:1"/>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Expanded">
                    <Storyboard>
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
                                                       Storyboard.TargetName="_expanderContent">
                            <DiscreteDoubleKeyFrame KeyTime="0" Value="NaN"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Collapsed"/>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <!-- ... --->
    

    That should be all that is necessary, the fluid layout will create the transition for you from there.


    If you have a code-behind solution that would be fine, you can even use code-behind in dictionaries like this:

    <!-- TestDictionary.xaml -->
    <ResourceDictionary x:Class="Test.TestDictionary"
                        ...>
    
    //TestDictionary.xaml.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    
    namespace Test
    {
        partial class TestDictionary : ResourceDictionary
        {
            //Handlers and such here
        }
    }
    
    0 讨论(0)
  • 2020-12-15 10:03

    This is kind of an old question but I had problems with this today, so I guess posting my solution would be worth it:

    I had to animate the Height property of a grid row (sliding up and down), but needed dynamic binding so that the row would slide again to the same position as before.

    I found this answer to be very helpful (after fruitlessly battling XAML): http://go4answers.webhost4life.com/Question/found-solution-work-protected-override-190845.aspx

    Sometimes doing things in the code-behind is just simpler:

            Storyboard sb = new Storyboard();
    
            var animation = new GridLengthAnimation
            {
                    Duration = new Duration(500.Milliseconds()),
                    From = this.myGridRow.Height,
                    To = new GridLength(IsGridRowVisible ? GridRowPreviousHeight : 0, GridUnitType.Pixel)
            };
    
            // Set the target of the animation
            Storyboard.SetTarget(animation, this.myGridRow);
            Storyboard.SetTargetProperty(animation, new PropertyPath("Height"));
    
            // Kick the animation off
            sb.Children.Add(animation);
            sb.Begin();
    

    The GridLengthAnimation class can be found here: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/da47a4b8-4d39-4d6e-a570-7dbe51a842e4/

    0 讨论(0)
  • 2020-12-15 10:03

    There is a ready-to-use and XAML-only solution on CodeProject:

    The Styles:

        <local:MultiplyConverter x:Key="MultiplyConverter" />
        <Style TargetType="Expander" x:Key="VerticalSlidingEmptyExpander">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <ScrollViewer x:Name="ExpanderContentScrollView"
                      HorizontalScrollBarVisibility="Hidden"
                      VerticalScrollBarVisibility="Hidden"
                      HorizontalContentAlignment="Stretch"
                      VerticalContentAlignment="Top"
                      >
                            <ScrollViewer.Tag>
                                <system:Double>0.0</system:Double>
                            </ScrollViewer.Tag>
                            <ScrollViewer.Height>
                                <MultiBinding Converter="{StaticResource MultiplyConverter}">
                                    <Binding Path="ActualHeight" ElementName="ExpanderContent"/>
                                    <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
                                </MultiBinding>
                            </ScrollViewer.Height>
                            <ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
                        </ScrollViewer>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="True">
                                <Trigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation 
                           Storyboard.TargetName="ExpanderContentScrollView"
                           Storyboard.TargetProperty="Tag"
                           To="1"
                           Duration="0:0:0.2"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation 
                             Storyboard.TargetName="ExpanderContentScrollView"
                             Storyboard.TargetProperty="Tag"
                             To="0"
                             Duration="0:0:0.2"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="Expander" x:Key="HorizontalSlidingEmptyExpander">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <ScrollViewer x:Name="ExpanderContentScrollView"
                      HorizontalScrollBarVisibility="Hidden"
                      VerticalScrollBarVisibility="Hidden"
                      HorizontalContentAlignment="Left"
                      VerticalContentAlignment="Stretch"
                      >
                            <ScrollViewer.Tag>
                                <system:Double>0.0</system:Double>
                            </ScrollViewer.Tag>
                            <ScrollViewer.Width>
                                <MultiBinding Converter="{StaticResource MultiplyConverter}">
                                    <Binding Path="ActualWidth" ElementName="ExpanderContent"/>
                                    <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
                                </MultiBinding>
                            </ScrollViewer.Width>
                            <ContentPresenter x:Name="ExpanderContent" ContentSource="Content"/>
                        </ScrollViewer>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="True">
                                <Trigger.EnterActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation 
                           Storyboard.TargetName="ExpanderContentScrollView"
                           Storyboard.TargetProperty="Tag"
                           To="1"
                           Duration="0:0:0.2"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation 
                             Storyboard.TargetName="ExpanderContentScrollView"
                             Storyboard.TargetProperty="Tag"
                             To="0"
                             Duration="0:0:0.2"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    MultiplyConverter:

    public class MultiplyConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType,
               object parameter, CultureInfo culture)
        {
            double result = 1.0;
            for (int i = 0; i < values.Length; i++)
            {
                if (values[i] is double)
                    result *= (double)values[i];
            }
    
            return result;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes,
               object parameter, CultureInfo culture)
        {
            throw new Exception("Not implemented");
        }
    }
    

    I duplicated the Style to have a horizontal and vertical version and omitted the ToggleButtons, but you can easily get that from the original post.

    0 讨论(0)
提交回复
热议问题