2010-08-12 104 views
0

我正在學習WPF動畫,並用一個非常簡單的動畫創建了一個簡單的演示應用程序。我已將主柵格分爲三行;頂部的按鈕行,以及屏幕剩餘部分的兩個內容行,一個紅色和一個藍色。完整的XAML如下。爲什麼不能使用此動畫?

有兩個按鈕,顯示紅色和顯示藍色。當每個按鈕被按下時,我希望按鈕行下方的區域通過緩慢的從上到下的擦拭來改變顏色。故事板設置兩行,以0的高度,然後動畫所需的行到1×的高度,這樣的:

<Storyboard> 
    <Utility:GridLengthAnimation Storyboard.TargetName="RedRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
    <Utility:GridLengthAnimation Storyboard.TargetName="BlueRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
    <Utility:GridLengthAnimation Storyboard.TargetName="BlueRow" Storyboard.TargetProperty="Height" From="0" To="1*" Duration="0:0:5" /> 
</Storyboard> 

的顏色改變爲預期的,但沒有動畫。所以,我的問題很簡單:爲什麼不動畫工作?

我正在使用自定義動畫類GridLengthAnimation(改編自this CodeProject article)爲網格長度設置動畫。我已經複製了下面的課程。

要重新創建演示項目:要重新創建我的演示項目,創建一個新的WPF項目(我用VS 2010)並用以下替換XAML中MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Utility="clr-namespace:Utility" Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Name="Buttons" Height="35" /> 
      <RowDefinition Name="RedRow" Height="0.5*" /> 
      <RowDefinition Name="BlueRow" Height="0.5*" /> 
     </Grid.RowDefinitions> 

     <!-- Buttons --> 
     <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> 
      <Button Content="Show Red" Width="100" Margin="5" > 
       <Button.Triggers> 
        <EventTrigger RoutedEvent="Button.Click"> 
         <EventTrigger.Actions> 
          <BeginStoryboard> 
           <Storyboard> 
            <Utility:GridLengthAnimation Storyboard.TargetName="RedRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
            <Utility:GridLengthAnimation Storyboard.TargetName="BlueRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
            <Utility:GridLengthAnimation Storyboard.TargetName="RedRow" Storyboard.TargetProperty="Height" From="0" To="1*" Duration="0:0:5" /> 
           </Storyboard> 
          </BeginStoryboard> 
         </EventTrigger.Actions> 
        </EventTrigger> 
       </Button.Triggers> 
      </Button> 
      <Button Content="Show Blue" Width="100" Margin="5" > 
       <Button.Triggers> 
        <EventTrigger RoutedEvent="Button.Click"> 
         <EventTrigger.Actions> 
          <BeginStoryboard> 
           <Storyboard> 
            <Utility:GridLengthAnimation Storyboard.TargetName="RedRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
            <Utility:GridLengthAnimation Storyboard.TargetName="BlueRow" Storyboard.TargetProperty="Height" To="0" Duration="0:0:0" /> 
            <Utility:GridLengthAnimation Storyboard.TargetName="BlueRow" Storyboard.TargetProperty="Height" From="0" To="1*" Duration="0:0:5" /> 
           </Storyboard> 
          </BeginStoryboard> 
         </EventTrigger.Actions> 
        </EventTrigger> 
       </Button.Triggers> 
      </Button> 
     </StackPanel> 

     <!-- Grid Fills--> 
     <Border Grid.Row="1" Background="Red" /> 
     <Border Grid.Row="2" Background="Blue" /> 

    </Grid> 
</Window> 

沒有代碼 - 後面加入了MainWindow.xaml

將C#類添加到名爲GridLengthAnimation.cs的項目中。用以下代碼替換該類中的代碼:

using System; 
using System.Windows.Media.Animation; 
using System.Windows; 

namespace Utility 
{ 
    /// <summary> 
    /// Enables animation of WPF Grid row heights and column widths. 
    /// </summary> 
    /// <remarks>Adapted from Graus & Sivakumar, "WPF Tutorial - Part 2 : Writing a custom animation class", 
    /// http://www.codeproject.com/KB/WPF/GridLengthAnimation.aspx, retrieved 08/12/2010.</remarks> 
    internal class GridLengthAnimation : AnimationTimeline 
    { 
     static GridLengthAnimation() 
     { 
      FromProperty = DependencyProperty.Register("From", typeof(GridLength), 
       typeof(GridLengthAnimation)); 

      ToProperty = DependencyProperty.Register("To", typeof(GridLength), 
       typeof(GridLengthAnimation)); 
     } 

     public override Type TargetPropertyType 
     { 
      get 
      { 
       return typeof(GridLength); 
      } 
     } 

     protected override Freezable CreateInstanceCore() 
     { 
      return new GridLengthAnimation(); 
     } 

     public static readonly DependencyProperty FromProperty; 
     public GridLength From 
     { 
      get 
      { 
       return (GridLength)GetValue(FromProperty); 
      } 
      set 
      { 
       SetValue(FromProperty, value); 
      } 
     } 

     public static readonly DependencyProperty ToProperty; 
     public GridLength To 
     { 
      get 
      { 
       return (GridLength)GetValue(ToProperty); 
      } 
      set 
      { 
       SetValue(ToProperty, value); 
      } 
     } 

     public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) 
     { 
      double fromVal = ((GridLength)GetValue(FromProperty)).Value; 
      double toVal = ((GridLength)GetValue(ToProperty)).Value; 

      if (animationClock.CurrentProgress != null) 
      { 
       if (fromVal > toVal) 
       { 
        return new GridLength((1 - animationClock.CurrentProgress.Value) * (fromVal - toVal) + toVal, GridUnitType.Star); 
       } 
       else 
       { 
        return new GridLength(animationClock.CurrentProgress.Value * (toVal - fromVal) + fromVal, GridUnitType.Star); 
       } 
      } 
      else 
      { 
       return null; 
      } 
     } 
    } 
} 

回答

0

我在this blog post找到了我的答案。事實證明,動畫高度或寬度屬性存在問題。我通過使用溶解效果而不是擦拭來解決問題。要製作解散動畫,請將兩個控件聲明在同一個網格行和列中,這會將它們加載到彼此的頂部。最後聲明默認控件,這將使其成爲可見控件。然後,將默認控件的「不透明度」值設置爲零以隱藏它,然後回到1以顯示它。

如果要動畫的控件是用戶控件或其他控件,您需要點擊一下,則需要再執行一步。這是因爲將控件的不透明度設置爲零隻是使其不可見。它仍然會阻止點擊它下面的控件。因此,在默認控件上聲明一個Render.Transform,然後爲ScaleY屬性設置動畫,以便在不可見時將其設置爲0,在顯示時將其設置爲1。

下面是我正在開發的生產應用程序的一個示例。它在資源管理器風格界面的導航器窗格中在註釋列表和日曆(兩個不同的用戶控件)之間切換。下面是兩個控件的聲明:

<!-- ClientArea: Navigator --> 
<Grid x:Name="Navigator"> 
    <View:CalendarNavigator x:Name="Calendar" /> 
    <View:NoteListNavigator x:Name="NoteList"> 
     <View:NoteListNavigator.RenderTransform> 
      <ScaleTransform ScaleX="1" ScaleY="1" /> 
     </View:NoteListNavigator.RenderTransform> 
    </View:NoteListNavigator> 
</Grid> 

注意ScaleTransform便箋列表上的聲明。我用了幾個功能區按鈕的兩個用戶控件之間切換:

<ribbon:RibbonToggleButton x:Name="NoteListViewButton" LargeImageSource="..\Images\ListViewLarge.png" SmallImageSource="..\Images\ListViewSmall.png" Label="Note List" Click="OnViewButtonClick"> 
    <ribbon:RibbonToggleButton.Triggers> 
     <EventTrigger RoutedEvent="ribbon:RibbonToggleButton.Checked"> 
      <EventTrigger.Actions> 
       <BeginStoryboard> 
        <Storyboard> 
         <DoubleAnimation Storyboard.TargetName="NoteList" Storyboard.TargetProperty="(View:NoteListNavigator.RenderTransform).(ScaleTransform.ScaleY)" To="1" Duration="0:0:0" /> 
         <DoubleAnimation Storyboard.TargetName="NoteList" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1" /> 
        </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger.Actions> 
     </EventTrigger> 
     </ribbon:RibbonToggleButton.Triggers> 
</ribbon:RibbonToggleButton> 

<ribbon:RibbonToggleButton x:Name="CalendarViewButton" LargeImageSource="..\Images\CalendarViewLarge.png" SmallImageSource="..\Images\CalendarViewSmall.png" Label="Calendar" Click="OnViewButtonClick"> 
    <ribbon:RibbonToggleButton.Triggers> 
     <EventTrigger RoutedEvent="ribbon:RibbonToggleButton.Checked"> 
      <EventTrigger.Actions> 
       <BeginStoryboard> 
        <Storyboard> 
         <DoubleAnimation Storyboard.TargetName="NoteList" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:1" /> 
         <DoubleAnimation Storyboard.TargetName="NoteList" Storyboard.TargetProperty="(View:NoteListNavigator.RenderTransform).(ScaleTransform.ScaleY)" To="0" Duration="0:0:0" /> 
        </Storyboard> 
       </BeginStoryboard> 
      </EventTrigger.Actions> 
     </EventTrigger> 
    </ribbon:RibbonToggleButton.Triggers> 
</ribbon:RibbonToggleButton> 

則scaleY轉變得到了無形的筆記列表的方式進行時,日曆顯示,這樣我可以點擊我的日曆控件。請注意,我需要對Storyboard中的ScaleY屬性進行完全限定的引用。這就是爲什麼引用括在括號中的原因。

希望能幫助其他人在路上!這很可能是我,因爲我可能會忘記我是怎麼做到的......