2010-07-05 48 views

回答

4

ColumnDefinition.WidthRowDefinition.Height属性类型为GridLength,并且此类型没有内置动画。所以如果你想这样做,你可能需要创建自己的GridLengthAnimation类。这可能不是太不可能的,如果你把DoubleAnimation作为一个例子,但也不容易......

编辑:实际上,有几个有趣的结果,如果你搜索在谷歌“GridLength动画” ......

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

第一个链接帮助我分配,谢谢:) – 2012-04-12 05:11:17

+4

Annnd ...“windowsclient.net”链接被破坏。看起来好像MS在Win8之前拆除任何东西,或者使用Hanlon的Razor,根本不在意它。 – codekaizen 2012-12-10 20:39:16

+0

第一个链接[由Wayback Machine保存](http://web.archive.org/web/20111201124746/http://windowsclient.net/learn/video.aspx?v=70654) – fernio 2017-03-16 20:44:43

4

我累了具有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(); 
    } 
+5

你使用的gridlengthanimation类是什么? – koenmetsu 2012-11-10 10:04:43

+0

它来自这个回复https://stackoverflow.com/a/3181521/4065368 - 最后一个链接 - 只是修改了一下 – stambikk 2017-10-11 00:28:52

4

我建立在由佰肖提供的AnimationHelper类和包裹在可重复使用的GridAnimationBehavior其可附接至RowDefinitionColumnDefinition元件。

/// <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的码比特以使用型时间跨度的参数为动画的持续时间,而不是独立的秒和毫秒参数。

此行为使网格行/列MVVM友好的动画(仅XAML,没有后面的代码需要)。示例:

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

我添加了此答案,因为原始海报要求提供纯XAML解决方案。

17

工作情况如何?为什么不在你想要动画的特定行内放置一个网格(或任何其他所需的控件),将行高设置为“Auto”,然后为控件的高度设置动画。它为我工作。

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

我承认它不是你在找什么。但它是一个快速解决方案(当然,假设最终你希望UIElement放置在通过网格行动画生成动画的网格中)。你可以同样做它的列宽。

+0

这是迄今为止最简单的方法......工作得非常好,代码/麻烦最少。 – AshbyEngineer 2014-07-13 17:42:09

0

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>