2010-07-05 12 views

Odpowiedz

4

Właściwości ColumnDefinition.Width i RowDefinition.Height są typu GridLength i nie ma wbudowanych animacji dla tego typu. Więc jeśli chcesz to zrobić, prawdopodobnie będziesz musiał stworzyć własną klasę GridLengthAnimation. To nie jest chyba zbyt niemożliwe, jeśli wziąć DoubleAnimation jako przykład, ale nie jest łatwe albo ...

EDIT: faktycznie, istnieje kilka interesujących wyników, jeśli szukać „animacja GridLength” na 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

Pierwszy link pomógł mi przydzielić, dzięki :) –

+4

Annnd ... link "windowsclient.net" jest zepsuty. Wygląda na to, że stwardnienie rozsiane demontuje cokolwiek przed Win8 lub stosując Brzytwa Hanlona, ​​po prostu nie dba o to. – codekaizen

+0

Pierwszy link został [zapisany przez maszynę Wayback] (http://web.archive.org/web/20111201124746/http://windowsclient.net/learn/video.aspx?v=70654) – fernio

4

dostałem zmęczony konieczności skrzypce z XAML do animowania siatki wierszy i kolumn jakiś czas temu, więc napisałem kilka sposobów, aby to zrobić całkowicie z kodu.

Z nich można rozszerzać/kurczyć kolumn i wierszy z kodu z jednej linii:

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

Jedną ważną rzeczą, aby pamiętać to ustawienie animacji null na ukończeniu. Jeśli tego nie zrobisz, siatka będzie nadal kontrolowana przez animację po zakończeniu animacji. Może to być dobre, jeśli siatka nie ma rozgałęźnika, ale jeśli sieć ma rozgałęźnik i chcesz mieć możliwość zmiany rozmiaru ręcznie po zakończeniu animacji, musisz ustawić animację na wartość null po jej zakończeniu.

Oto metody:

/// <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

jaka jest używana klasa gridlengthanimation? – koenmetsu

+0

To z tej odpowiedzi https://stackoverflow.com/a/3181521/4065368 - ostatni link - właśnie zmodyfikowany nieco – stambikk

4

I zbudowany na klasy AnimationHelper dostarczonych przez Nigel Shaw i owinął je w jednorazowych GridAnimationBehavior które mogą być dołączone do RowDefinition i ColumnDefinition elementów.

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

pamiętać, że manipulowane kod Nigela trochę użyć parametr typu TimeSpan na czas trwania animacji zamiast odrębnych sekund i parametrów milisekund.

To zachowanie powoduje, że animacja wierszy/kolumn siatki jest przyjazna dla MVVM (tylko XAML, bez kodu za wymaganym). Przykład:

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

Dodałem tę odpowiedź, ponieważ oryginalny plakat poprosił o czyste rozwiązanie XAML.

17

Co powiesz na pracę? Po co umieszczać siatkę (lub dowolną inną pożądaną kontrolę) wewnątrz określonego wiersza, który chcesz animować, ustawić wysokość wiersza na "Auto", a następnie animować wysokość kontrolki. To zadziałało dla mnie.

<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> 

Kod za:

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

przyznaję jej nie to, czego szukasz. Ale jest to szybkie rozwiązanie (Zakładając oczywiście, że ostatecznie chcesz, aby UIElement umieszczony wewnątrz siatki był animowany przez animowanie rzędu siatki). Możesz podobnie zrobić dla szerokości kolumny.

+0

było to zdecydowanie najprostsze podejście ... działało bardzo ładnie, najmniejsza ilość kodu/kłopotów. – AshbyEngineer

0

Biblioteka MahApps.Metro ma wbudowaną kontrolę. Źródło można znaleźć 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> 
Powiązane problemy