Анимация столбца сетки или строки сетки в XAML? - PullRequest
13 голосов
/ 05 июля 2010

Можно ли как-нибудь анимировать ширину столбца сетки или высоту строки сетки из XAML?

Ответы [ 5 ]

18 голосов
/ 09 мая 2013

Как насчет работы?Почему бы не разместить сетку (или любой другой нужный элемент управления) внутри конкретной строки, которую вы хотите анимировать, установите высоту строки на «Авто», а затем анимируйте высоту элемента управления.Это сработало для меня.

<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);
  }
}

Я признаю, что это не то, что вы ищете.Но это быстрое решение (при условии, конечно, что в конечном итоге вы хотите, чтобы элемент UIE размещался внутри сетки, анимируемой анимацией строки сетки).Вы также можете сделать это для ширины столбца.

5 голосов
/ 11 сентября 2012

Мне уже давно надоело возиться с XAML для анимации строк и столбцов сетки, поэтому я написал несколько методов, чтобы сделать это полностью из кода.

С их помощью вы можете расширять / сжимать столбцы и строки из кода одной строкой:

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

Одна важная вещь, на которую следует обратить внимание, - установка анимации на ноль при завершении. Если вы этого не сделаете, сетка все еще находится под контролем анимации, когда анимация завершена. Это может быть хорошо, если сетка не имеет разделителя, но если сетка имеет разделитель, и вы хотите иметь возможность изменить его размер вручную после завершения анимации, тогда вы должны установить анимацию в 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 голосов
/ 04 января 2013

Я использовал класс 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);
      }
    }
  }
}

Обратите внимание, что я немного подправил код Найджела, чтобы использовать параметр типа TimeSpan для длительности анимации вместо отдельных параметров секунд и миллисекунд.

Это поведение делает анимацию строк / столбцов сетки дружественной к MVVM (только для XAML, код не требуется). Пример:

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

Я добавил этот ответ, потому что в оригинальном плакате было запрошено чистое решение XAML.

4 голосов
/ 05 июля 2010

Свойства ColumnDefinition.Width и RowDefinition.Height имеют тип GridLength, и для этого типа нет встроенных анимаций.Поэтому, если вы хотите это сделать, вам, вероятно, придется создать свой собственный класс GridLengthAnimation.Это, вероятно, не так уж и невозможно, если вы возьмете DoubleAnimation в качестве примера, но тоже не просто ...

РЕДАКТИРОВАТЬ: на самом деле, есть несколько интересных результатов, если вы ищете "GridLength animation" в Google ...

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

0 голосов
/ 28 июля 2017

Библиотека MahApps.Metro имеет встроенный элемент управления для этого.Источник можно найти здесь .

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...