代码之家  ›  专栏  ›  技术社区  ›  David Veeneman

为什么这个动画不起作用?

  •  0
  • David Veeneman  · 技术社区  · 14 年前

    我正在学习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>
    

    没有代码隐藏添加到 主窗口 .

    将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;
                }
            }
        }
    }
    
    1 回复  |  直到 10 年前
        1
  •  0
  •   David Veeneman    14 年前

    我的答案在 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转换会使不可见的笔记列表偏离方向,以便我可以单击日历控件。请注意,我需要对故事板中的scaley属性进行完全限定的引用。这就是为什么引用用括号括起来的原因。

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