2010-08-12 107 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属性进行完全限定的引用。这就是为什么引用括在括号中的原因。

希望能帮助其他人在路上!这很可能是我,因为我可能会忘记我是怎么做到的......