以编程方式使用动画

本文介绍如何通过程序代码动态操作Silverlight中的动画属性,包括通过名称访问动画、动态更改TargetName以及在代码中创建动画等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Silverlight
4(共 4)对本文的评价是有帮助 - 评价此主题

有时您可能要动态(即时)更改动画的属性。 例如,您可能要调整应用到对象的动画行为,这取决于对象当前在布局中的位置、对象包含何种内容等等。 可以通过使用程序代码(例如 C# 或 Visual Basic)动态操作动画。

本主题包括下列各节。

您应熟悉 Silverlight 动画。 有关简介,请参见动画概述

访问动画对象以更改其属性的最直接方法是:命名该动画对象,然后在代码中通过该名称引用它。 下面的示例包含一个 Ellipse,当您在屏幕上单击时它将显示动画效果。 为了实现此动画,在单击 Canvas 时,事件处理程序更改 PointAnimation 对象的 To 属性,然后启动动画。

运行此示例

<CanvasMouseLeftButtonDown="Handle_MouseDown"Background="Gray"Width="600"Height="500"><Canvas.Resources><Storyboardx:Name="myStoryboard"><!-- The PointAnimation has a name so it can be accessed
             from code. The To property is left out of the XAML
             because the value of To is determined in code. --><PointAnimationx:Name="myPointAnimation"Storyboard.TargetProperty="Center"Storyboard.TargetName="MyAnimatedEllipseGeometry"Duration="0:0:2"/></Storyboard></Canvas.Resources><PathFill="Blue"><Path.Data><!-- Describes an ellipse. --><EllipseGeometryx:Name="MyAnimatedEllipseGeometry"Center="200,100"RadiusX="15"RadiusY="15"/></Path.Data></Path></Canvas>
C#
VB
privatevoid Handle_MouseDown(object sender, MouseButtonEventArgs e)
{
    // Retrieve current mouse coordinates.double newX = e.GetPosition(null).X;
    double newY = e.GetPosition(null).Y;
    Point myPoint = new Point();
    myPoint.X = newX;
    myPoint.Y = newY;
    myPointAnimation.To = myPoint;
    myStoryboard.Begin();
}


使所有动画具有唯一的名称有时不易做到。 这时您可以使用集合来访问动画或动画的关键帧。 例如,如果要以编程方式访问 DoubleAnimationUsingKeyFrames 对象中的所有关键帧,可以使用与以下代码类似的代码:

<Canvas x:Name="parentCanvas" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  Width="600" Height="500" Background="Gray">
  <Canvas.Resources>
    <Storyboard x:Name="myStoryboard">
      <PointAnimationUsingKeyFrames
        x:Name="myPointAnimationUsingKeyFrames"
        Storyboard.TargetProperty="Center"
        Storyboard.TargetName="MyAnimatedEllipseGeometry"
        Duration="0:0:3">

          <!-- Set of keyframes -->
          <DiscretePointKeyFrame KeyTime="0:0:0" />
          <LinearPointKeyFrame KeyTime="0:0:0.5" />
          <SplinePointKeyFrame KeySpline="0.6,0.0 0.9,0.00" KeyTime="0:0:3" />
      </PointAnimationUsingKeyFrames>
    </Storyboard>

  </Canvas.Resources>

  <Path Fill="Blue">
    <Path.Data>

      <!-- Describes an ellipse. -->
      <EllipseGeometry x:Name="MyAnimatedEllipseGeometry"
        Center="200,100" RadiusX="15" RadiusY="15" />
    </Path.Data>
  </Path>
</Canvas>
C#
public void Handle_MouseDown(object sender, MouseEventArgs e)
{
    int i;
    for (i = 0; i < myPointAnimationUsingKeyFrames.KeyFrames.Count; i++)
    {
        // Do something with each keyframe; for example, set values.
    }
}

下面的示例与上一个示例类似,即在用户单击屏幕的地方出现椭圆,只是此示例中使用了关键帧。 对关键帧的集合进行迭代并为关键帧动态设置值,以便使椭圆动画出现在合适的位置。

运行此示例

<CanvasMouseLeftButtonDown="Handle_MouseDown"Width="600"Height="500"Background="Gray"><Canvas.Resources><Storyboardx:Name="myStoryboard"><PointAnimationUsingKeyFramesx:Name="myPointAnimationUsingKeyFrames"Storyboard.TargetProperty="Center"Storyboard.TargetName="MyAnimatedEllipseGeometry"Duration="0:0:3"><DiscretePointKeyFrameKeyTime="0:0:0"/><LinearPointKeyFrameKeyTime="0:0:0.5"/><SplinePointKeyFrameKeySpline="0.6,0.0 0.9,0.00"KeyTime="0:0:2"/></PointAnimationUsingKeyFrames></Storyboard></Canvas.Resources><PathFill="Blue"><Path.Data><!-- Describes an ellipse. --><EllipseGeometryx:Name="MyAnimatedEllipseGeometry"Center="200,100"RadiusX="15"RadiusY="15"/></Path.Data></Path></Canvas>
C#
VB
// Global variables that keep track of the end point// of the last animation.double lastX = 200;
double lastY = 100;
privatevoid Handle_MouseDown(object sender, MouseEventArgs e)
{
    // Retrieve current mouse coordinates.double newX = e.GetPosition(null).X;
    double newY = e.GetPosition(null).Y;

    int i;
    for (i = 0; i < myPointAnimationUsingKeyFrames.KeyFrames.Count; i++)
    {
        PointKeyFrame keyFrame = myPointAnimationUsingKeyFrames.KeyFrames[i];
        if (keyFrame.GetType().Name == "DiscretePointKeyFrame")
        {
            keyFrame.SetValue(DiscretePointKeyFrame.ValueProperty, new Point(lastX, lastY));
        }
        elseif (keyFrame.GetType().Name == "LinearPointKeyFrame")
        {

            // The LinearKeyFrame has a value that is part way to the // final end point. In addition, this value has to be on// the correct line; therefore, you need to use the line // formula y = mx + b to find the values of x and y.// Calculate the slope.double m = (newY - lastY) / (newX - lastX);

            // Calculate the y-intercept.double b = newY - (m * newX);

            // Set X to a third of the way to the end point.double intermediateX = lastX + (newX - lastX) / 3;

            // Find the value Y from X and the line formula.double intermediateY = (m * intermediateX) + b;

            // Set the keyframe value to the intermediate x and y value.
            keyFrame.SetValue(LinearPointKeyFrame.ValueProperty, 
                new Point(intermediateX, intermediateY));
        }
        elseif (keyFrame.GetType().Name == "SplinePointKeyFrame")
        {
            keyFrame.SetValue(SplinePointKeyFrame.ValueProperty, new Point(newX, newY));
        }
    }
    myStoryboard.Stop();
    myStoryboard.Begin();
    lastX = newX;
    lastY = newY;
}


注意说明:

Storyboard 具有 Children 属性,该属性允许您访问指定 Storyboard 中的所有动画对象。

动态更改 Storyboard.TargetName 属性最常见的情况是您想将同一动画应用到多个对象。 当具有要应用相似动画的大量对象时,这特别有用。 例如,您可能要显示几行图像并使用动画突出显示鼠标当前所指示的图像。 为每个图像创建单独的 Storyboard 对象非常麻烦。 重用同一 Storyboard 更为合适。

下面的示例涉及很多矩形,当您单击这些矩形时,它们会逐渐消失,接着重新显示。 所有这些矩形使用同一 Storyboard,因为呈现 Opacity 动画效果的DoubleAnimation 将 TargetName 更改为所单击的矩形。

运行此示例

<StackPanelOrientation="Horizontal"><StackPanel.Resources><Storyboardx:Name="myStoryboard"><DoubleAnimationx:Name="myDoubleAnimation"Storyboard.TargetProperty="Opacity"From="1.0"To="0.0"Duration="0:0:2"AutoReverse="True"/></Storyboard></StackPanel.Resources><Rectanglex:Name="MyAnimatedRectangle1"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle2"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle3"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle4"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/></StackPanel>
C#
VB
privatevoid Start_Animation(object sender, MouseEventArgs e)
{

    // If the Storyboard is running and you try to change// properties of its animation objects programmatically, // an error will occur.
    myStoryboard.Stop();

    // Get a reference to the rectangle that was clicked.
    Rectangle myRect = (Rectangle)sender;

    // Change the TargetName of the animation to the name of the// rectangle that was clicked.
    myDoubleAnimation.SetValue(Storyboard.TargetNameProperty, myRect.Name);

    // Begin the animation.
    myStoryboard.Begin();
}


在前面的代码中,请注意您在动态更改动画对象的属性前必须停止 Storyboard,否则将出错。 在此示例中,可能不希望只有停止一个矩形的动画才能启动另一个矩形的动画。 可能您想同时运行这两个动画。 但是,您不能使用同一个动画对象同时运行两个独立的动画,因为只有一个 TargetName 这并不意味着您不得不重新为每个对象创建单独的 Storyboard 您只需要为并发(同步)运行的每个动画提供一个 Storyboard 下面的示例与上一个示例类似,只是它包含三个而不是一个Storyboard 对象。 您单击矩形时,事件处理程序查找当前未使用的 Storyboard 并使用它来创建动画。

运行此示例

<StackPanelOrientation="Horizontal"><StackPanel.Resources><Storyboardx:Name="myStoryboard1"Completed="Storyboard_Completed"><DoubleAnimationx:Name="myDoubleAnimation1"Storyboard.TargetProperty="Opacity"From="1.0"To="0.0"Duration="0:0:2"AutoReverse="True"/></Storyboard><Storyboardx:Name="myStoryboard2"Completed="Storyboard_Completed"><DoubleAnimationx:Name="myDoubleAnimation2"Storyboard.TargetProperty="Opacity"From="1.0"To="0.0"Duration="0:0:2"AutoReverse="True"/></Storyboard><Storyboardx:Name="myStoryboard3"Completed="Storyboard_Completed"><DoubleAnimationx:Name="myDoubleAnimation3"Storyboard.TargetProperty="Opacity"From="1.0"To="0.0"Duration="0:0:2"AutoReverse="True"/></Storyboard></StackPanel.Resources><Rectanglex:Name="MyAnimatedRectangle1"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle2"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle3"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/><Rectanglex:Name="MyAnimatedRectangle4"Margin="3"Width="100"Height="100"Fill="Blue"MouseLeftButtonDown="Start_Animation"/></StackPanel>
C#
VB
bool storyboard1Active = false;
bool storyboard2Active = false;
bool storyboard3Active = false;

privatevoid Start_Animation(object sender, MouseEventArgs e)
{
    // Get a reference to the rectangle that was clicked.
    Rectangle myRect = (Rectangle)sender;
    if (!storyboard1Active)
    {
        myStoryboard1.Stop();
        myDoubleAnimation1.SetValue(Storyboard.TargetNameProperty, myRect.Name);
        myStoryboard1.Begin();
        storyboard1Active = true;
    }
    elseif (!storyboard2Active)
    {
        myStoryboard2.Stop();
        myDoubleAnimation2.SetValue(Storyboard.TargetNameProperty, myRect.Name);
        myStoryboard2.Begin();
        storyboard2Active = true;
    }
    elseif (!storyboard3Active)
    {
        myStoryboard3.Stop();
        myDoubleAnimation3.SetValue(Storyboard.TargetNameProperty, myRect.Name);
        myStoryboard3.Begin();
        storyboard3Active = true;
    }
}

privatevoid Storyboard_Completed(object sender, EventArgs e)
{
    Storyboard myStoryboard = sender as Storyboard;
    switch (myStoryboard.GetValue(NameProperty).ToString())
    {
        case"myStoryboard1": storyboard1Active = false; break;

        case"myStoryboard2": storyboard2Active = false; break;

        case"myStoryboard3": storyboard3Active = false; break;
    }
}


在上面的示例中,同时只能运行三个动画(等于 Storyboard 对象的数目)。 如果您不需要同时运行更多动画,这个示例就可以满足要求了,否则将需要更多的Storyboard 对象。 如果要同时运行很多独立的动画,可能要动态创建 Storyboard 对象。 有关在代码中创建演示图板对象的示例,请参见下一节。

您还可以完全在程序代码中创建动画。 下面的示例演示如何创建一个动画,在其中用动画呈现矩形的 Canvas.Top 和 Canvas.Left 附加属性。

运行此示例

C#
VB
private void Create_And_Run_Animation(object sender, EventArgs e)
{
    // Create a red rectangle that will be the target
    // of the animation.
    Rectangle myRectangle = new Rectangle();
    myRectangle.Width = 200;
    myRectangle.Height = 200;
    Color myColor = Color.FromArgb(255, 255, 0, 0);
    SolidColorBrush myBrush = new SolidColorBrush();
    myBrush.Color = myColor;
    myRectangle.Fill = myBrush;

    // Add the rectangle to the tree.
    LayoutRoot.Children.Add(myRectangle);

    // Create a duration of 2 seconds.
    Duration duration = new Duration(TimeSpan.FromSeconds(2));

    // Create two DoubleAnimations and set their properties.
    DoubleAnimation myDoubleAnimation1 = new DoubleAnimation();
    DoubleAnimation myDoubleAnimation2 = new DoubleAnimation();

    myDoubleAnimation1.Duration = duration;
    myDoubleAnimation2.Duration = duration;

    Storyboard sb = new Storyboard();
    sb.Duration = duration;

    sb.Children.Add(myDoubleAnimation1);
    sb.Children.Add(myDoubleAnimation2);

    Storyboard.SetTarget(myDoubleAnimation1, myRectangle);
    Storyboard.SetTarget(myDoubleAnimation2, myRectangle);

    // Set the attached properties of Canvas.Left and Canvas.Top
    // to be the target properties of the two respective DoubleAnimations.
    Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath("(Canvas.Left)"));
    Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath("(Canvas.Top)"));

    myDoubleAnimation1.To = 200;
    myDoubleAnimation2.To = 200;

    // Make the Storyboard a resource.
    LayoutRoot.Resources.Add("unique_id", sb);

    // Begin the animation.
    sb.Begin();
}


注意 说明:

不要试图在页面的构造函数中调用 Storyboard 成员(例如 Begin 方法)。 这将导致动画失败,且无任何提示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值