代码之家  ›  专栏  ›  技术社区  ›  Kishore Kumar

在XAML中设置网格列或网格行的动画?

wpf
  •  12
  • Kishore Kumar  · 技术社区  · 15 年前

    有什么方法可以从XAML设置网格列宽或网格行高的动画吗?

    5 回复  |  直到 9 年前
        1
  •  5
  •   Thomas Levesque    15 年前

    ColumnDefinition.Width RowDefinition.Height GridLength ,并且没有此类型的内置动画。因此,如果你想这样做,你可能必须创建自己的 GridLengthAnimation 班级。如果你采取 DoubleAnimation 举个例子,但也不容易。。。

    http://windowsclient.net/learn/video.aspx?v=70654
    http://marlongrech.wordpress.com/2007/08/20/gridlength-animation/
    http://www.codeproject.com/KB/WPF/GridLengthAnimation.aspx

        2
  •  18
  •   MithunSV    12 年前

    找个工作怎么样?为什么不在要设置动画的特定行中放置网格(或任何其他所需控件),将行高度设置为“自动”,然后设置控件高度的动画。它对我有用。

    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>
      <Button x:Name="ExpandCollapseBtn" Width="100" Click="ExpandCollapse_Click"/>
      <WrapPanel x:Name="ToolBox" Grid.Row="1" Height="0">
        <Button Content="1" Width="50" Height="50"/>
        <Button Content="2" Width="50" Height="50"/>
        <Button Content="3" Width="50" Height="50"/>
        <Button Content="4" Width="50" Height="50"/>
      </WrapPanel>
    </Grid>
    

    代码隐藏:

    private bool Expanded = false;
    void ExpandCollapse_Click(object sender, RoutedEventArgs e)
    {
      if (Expanded)
      {
        var anim = new DoubleAnimation(0, (Duration)TimeSpan.FromSeconds(0.3));
        anim.Completed += (s, _) => Expanded = false;
        ToolBox.BeginAnimation(ContentControl.HeightProperty, anim);
      }
      else
      {
        var anim = new DoubleAnimation(100, (Duration)TimeSpan.FromSeconds(0.3));
        anim.Completed += (s, _) => Expanded = true;
        ToolBox.BeginAnimation(ContentControl.HeightProperty, anim);
      }
    }
    

        3
  •  5
  •   Nigel Shaw    13 年前

    不久前,我厌倦了用XAML来制作网格行和列的动画,所以我编写了几个方法完全从代码中完成。

    通过这些,您可以用一行代码展开/收缩列和行:

    Animation.AnimationHelper.AnimateGridColumnExpandCollapse(LeftColumn, true, expandedHeight, currentWidth, LeftColumn.MinWidth, 0, 200);
    

    需要注意的一点是在完成时将动画设置为null。如果不执行此操作,则动画完成后网格仍在动画的控制下。如果网格没有拆分器,这可能很好,但是如果网格有拆分器并且您希望能够在动画完成后手动调整其大小,则必须在动画完成后将其设置为null。

    方法如下:

        /// <summary>
        /// Animate expand/collapse of a grid column. 
        /// </summary>
        /// <param name="gridColumn">The grid column to expand/collapse.</param>
        /// <param name="expandedWidth">The expanded width.</param>
        /// <param name="milliseconds">The milliseconds component of the duration.</param>
        /// <param name="collapsedWidth">The width when collapsed.</param>
        /// <param name="minWidth">The minimum width of the column.</param>
        /// <param name="seconds">The seconds component of the duration.</param>
        /// <param name="expand">If true, expand, otherwise collapse.</param>
        public static void AnimateGridColumnExpandCollapse(ColumnDefinition gridColumn, bool expand, double expandedWidth, double collapsedWidth, 
            double minWidth, int seconds, int milliseconds)
        {
            if( expand && gridColumn.ActualWidth >= expandedWidth)
                // It's as wide as it needs to be.
                return;
    
            if (!expand && gridColumn.ActualWidth == collapsedWidth)
                // It's already collapsed.
                return;
    
            Storyboard storyBoard = new Storyboard();
    
            GridLengthAnimation animation = new GridLengthAnimation();
            animation.From = new GridLength(gridColumn.ActualWidth);
            animation.To = new GridLength(expand ? expandedWidth : collapsedWidth);
            animation.Duration = new TimeSpan(0, 0, 0, seconds, milliseconds);
    
            // Set delegate that will fire on completion.
            animation.Completed += delegate
            {
                // Set the animation to null on completion. This allows the grid to be resized manually
                gridColumn.BeginAnimation(ColumnDefinition.WidthProperty, null);
    
                // Set the final value manually.
                gridColumn.Width = new GridLength(expand ? expandedWidth : collapsedWidth);
    
                // Set the minimum width.
                gridColumn.MinWidth = minWidth;
            };
    
            storyBoard.Children.Add(animation);
    
            Storyboard.SetTarget(animation, gridColumn);
            Storyboard.SetTargetProperty(animation, new PropertyPath(ColumnDefinition.WidthProperty));
            storyBoard.Children.Add(animation);
    
            // Begin the animation.
            storyBoard.Begin();
        }
    
        /// <summary>
        /// Animate expand/collapse of a grid row. 
        /// </summary>
        /// <param name="gridRow">The grid row to expand/collapse.</param>
        /// <param name="expandedHeight">The expanded height.</param>
        /// <param name="collapsedHeight">The collapesed height.</param>
        /// <param name="minHeight">The minimum height.</param>
        /// <param name="milliseconds">The milliseconds component of the duration.</param>
        /// <param name="seconds">The seconds component of the duration.</param>
        /// <param name="expand">If true, expand, otherwise collapse.</param>
        public static void AnimateGridRowExpandCollapse(RowDefinition gridRow, bool expand, double expandedHeight, double collapsedHeight, double minHeight, int seconds, int milliseconds)
        {
            if (expand && gridRow.ActualHeight >= expandedHeight)
                // It's as high as it needs to be.
                return;
    
            if (!expand && gridRow.ActualHeight == collapsedHeight)
                // It's already collapsed.
                return;
    
            Storyboard storyBoard = new Storyboard();
    
            GridLengthAnimation animation = new GridLengthAnimation();
            animation.From = new GridLength(gridRow.ActualHeight);
            animation.To = new GridLength(expand ? expandedHeight : collapsedHeight);
            animation.Duration = new TimeSpan(0, 0, 0, seconds, milliseconds);
    
            // Set delegate that will fire on completioon.
            animation.Completed += delegate
            {
                // Set the animation to null on completion. This allows the grid to be resized manually
                gridRow.BeginAnimation(RowDefinition.HeightProperty, null);
    
                // Set the final height.
                gridRow.Height = new GridLength(expand ? expandedHeight : collapsedHeight);
    
                // Set the minimum height.
                gridRow.MinHeight = minHeight;
            };
    
            storyBoard.Children.Add(animation);
    
            Storyboard.SetTarget(animation, gridRow);
            Storyboard.SetTargetProperty(animation, new PropertyPath(RowDefinition.HeightProperty));
            storyBoard.Children.Add(animation);
    
            // Begin the animation.
            storyBoard.Begin();
        }
    
        4
  •  4
  •   candritzky    13 年前

    AnimationHelper GridAnimationBehavior 可以连接到 RowDefinition ColumnDefinition 元素。

    /// <summary>
    /// Wraps the functionality provided by the <see cref="AnimationHelper"/> class
    /// in a behavior which can be used with the <see cref="ColumnDefinition"/>
    /// and <see cref="RowDefinition"/> types.
    /// </summary>
    public class GridAnimationBehavior : DependencyObject
    {
      #region Attached IsExpanded DependencyProperty
    
      /// <summary>
      /// Register the "IsExpanded" attached property and the "OnIsExpanded" callback 
      /// </summary>
      public static readonly DependencyProperty IsExpandedProperty =
        DependencyProperty.RegisterAttached("IsExpanded", typeof(bool), typeof(GridAnimationBehavior),
          new FrameworkPropertyMetadata(OnIsExpandedChanged));
    
      public static void SetIsExpanded(DependencyObject dependencyObject, bool value)
      {
        dependencyObject.SetValue(IsExpandedProperty, value);
      }
    
      #endregion
    
      #region Attached Duration DependencyProperty
    
      /// <summary>
      /// Register the "Duration" attached property 
      /// </summary>
      public static readonly DependencyProperty DurationProperty =
        DependencyProperty.RegisterAttached("Duration", typeof(TimeSpan), typeof(GridAnimationBehavior),
          new FrameworkPropertyMetadata(TimeSpan.FromMilliseconds(200)));
    
      public static void SetDuration(DependencyObject dependencyObject, TimeSpan value)
      {
        dependencyObject.SetValue(DurationProperty, value);
      }
    
      private static TimeSpan GetDuration(DependencyObject dependencyObject)
      {
        return (TimeSpan)dependencyObject.GetValue(DurationProperty);
      }
    
      #endregion
    
      #region GridCellSize DependencyProperty
    
      /// <summary>
      /// Use a private "GridCellSize" dependency property as a temporary backing 
      /// store for the last expanded grid cell size (row height or column width).
      /// </summary>
      private static readonly DependencyProperty GridCellSizeProperty =
        DependencyProperty.Register("GridCellSize", typeof(double), typeof(GridAnimationBehavior),
          new UIPropertyMetadata(0.0));
    
      private static void SetGridCellSize(DependencyObject dependencyObject, double value)
      {
        dependencyObject.SetValue(GridCellSizeProperty, value);
      }
    
      private static double GetGridCellSize(DependencyObject dependencyObject)
      {
        return (double)dependencyObject.GetValue(GridCellSizeProperty);
      }
    
      #endregion
    
      /// <summary>
      /// Called when the attached <c>IsExpanded</c> property changed.
      /// </summary>
      private static void OnIsExpandedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
      {
        var duration = GetDuration(dependencyObject);
        var rowDefinition = dependencyObject as RowDefinition;
        if (rowDefinition != null)
        {
          // The IsExpanded attached property of a RowDefinition changed
          if ((bool)e.NewValue)
          {
            var expandedHeight = GetGridCellSize(rowDefinition);
            if (expandedHeight > 0)
            {
              // Animate row height back to saved expanded height.
              AnimationHelper.AnimateGridRowExpandCollapse(rowDefinition, true, expandedHeight, rowDefinition.ActualHeight, 0, duration);
            }
          }
          else
          {
            // Save expanded height and animate row height down to zero.
            SetGridCellSize(rowDefinition, rowDefinition.ActualHeight);
            AnimationHelper.AnimateGridRowExpandCollapse(rowDefinition, false, rowDefinition.ActualHeight, 0, 0, duration);
          }
        }
    
        var columnDefinition = dependencyObject as ColumnDefinition;
        if (columnDefinition != null)
        {
          // The IsExpanded attached property of a ColumnDefinition changed
          if ((bool)e.NewValue)
          {
            var expandedWidth = GetGridCellSize(columnDefinition);
            if (expandedWidth > 0)
            {
              // Animate column width back to saved expanded width.
              AnimationHelper.AnimateGridColumnExpandCollapse(columnDefinition, true, expandedWidth, columnDefinition.ActualWidth, 0, duration);
            }
          }
          else
          {
            // Save expanded width and animate column width down to zero.
            SetGridCellSize(columnDefinition, columnDefinition.ActualWidth);
            AnimationHelper.AnimateGridColumnExpandCollapse(columnDefinition, false, columnDefinition.ActualWidth, 0, 0, duration);
          }
        }
      }
    }
    

    请注意,我对Nigel的代码进行了一些调整,在动画持续时间中使用了TimeSpan类型的参数,而不是单独的秒和毫秒参数。

    <Grid.RowDefinitions>
      <RowDefinition Height="*" Behaviors:GridAnimationBehavior.IsExpanded="{Binding IsUpperPaneVisible}" />
      <RowDefinition Height="*" />
      <RowDefinition Height="*" Behaviors:GridAnimationBehavior.IsExpanded="{Binding IsLowerPaneVisible}" />
    </Grid.RowDefinitions>
    

    我添加这个答案是因为最初的海报要求纯XAML解决方案。

        5
  •  1
  •   Matt Williams    8 年前

    这个 MahApps.Metro 库对此具有内置控件。可以找到源头 here .

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="48" x:Name="HamburgerMenuColumn" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    
        <Grid.Resources>
            <Storyboard x:Key="CloseMenu" Storyboard.TargetName="HamburgerMenuColumn" Storyboard.TargetProperty="(ColumnDefinition.Width)">
                <metro:GridLengthAnimation To="48" Duration="00:00:00"></metro:GridLengthAnimation>
            </Storyboard>
         </Grid.Resources>
    </Grid>
    
        6
  •  0
  •   hitchao    5 年前

    这是我的工作

    在XAML中:

    <Grid >
        <Grid.RenderTransform>
            <TranslateTransform  />
        </Grid.RenderTransform>
    
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition x:Name="SecondRow"  Height="100"/>
        </Grid.RowDefinitions>
    </Grid >
    

    代码隐藏:

    if (SecondRow.Height == new GridLength(0))
    {
    
        Task.Run(() => {
            for(int i = 0; i <= 20; i++)
            {
                this.Dispatcher.Invoke((Action)delegate { SecondRow.Height = new GridLength(5*i); });
                Task.Delay(1).Wait();
            }
        });
    }
    else
    {
        Task.Run(() => {
            for (int i = 20; i >= 0; i--)
            {
                this.Dispatcher.Invoke((Action)delegate { SecondRow.Height = new GridLength(5 * i); });
                Task.Delay(1).Wait();
            }
        });
    }