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

时间:2010-08-12 19:26:21

标签: wpf xaml animation

我正在学习WPF动画,我创建了一个简单的演示应用程序,其中包含非常简单的动画。我将主网格划分为三行; a按钮在顶部排,两个内容行用于屏幕的其余部分,一个红色和一个蓝色。完整的XAML如下。

有两个按钮,Show Red和Show Blue。当按下每个按钮时,我希望按钮行下面的区域通过缓慢的从上到下的擦除来改变颜色。故事板将两行的高度设置为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)并将MainWindow.xaml中的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;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我在this blog post找到了答案。事实证明,设置高度或宽度属性存在问题。我通过使用溶解效果而不是擦除来解决问题。要为dissolve设置动画,请在同一Grid行和列中声明两个控件,这些控件将在彼此之上加载它们。最后声明默认控件,这将使其成为可见控件。然后,将默认控件的“不透明度”值设置为零以将其隐藏,并将其设置为1以显示它。

如果要设置动画的控件是UserControls或其他需要单击的控件,则需要再执行一步。这是因为将控件的不透明度设置为零只会使其不可见。它仍然会阻止点击它下面的控件。因此,在默认控件上声明一个Render.Transform,然后设置ScaleY属性的动画,使其在不可见时设置为0,在显示时设置为1.

以下是我正在制作的制作应用中的一个示例。它在资源管理器样式界面的“导航器”窗格中在注释列表和日历(两个不同的UserControl)之间切换。以下是两个控件的声明:

<!-- 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的声明。我使用一些功能区按钮在两个UserControls之间切换:

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

希望能帮助别人前进!这很可能是我,因为我可能会忘记我是怎么做到的......