如何使故事板淡入,暂停,然后淡出(通过代码)?

时间:2011-07-29 07:24:48

标签: c# silverlight

我写了以下代码。它尝试创建一个执行以下操作的故事板:

  1. 淡入500毫秒
  2. 暂停1000毫秒
  3. 淡出500毫秒
  4. 但是在运行时获取System.InvalidOperationException,后跟以下输出:

    Additional information: Multiple animations in 
      the same containing Storyboard cannot target the
      same property on a single element.
    

    这似乎表明它试图一次完成所有动画而不是顺序动画。

    private Storyboard createStoryboard()
    {
      Storyboard board = new Storyboard();
    
      addFadeToStoryboard(board, 0, 1, 500);
      addFadeToStoryboard(board, 1, 1, 1000);
    
      DoubleAnimation fadeOut = addFadeToStoryboard(board, 1, 0, 500);
    
      fadeOut.Completed += new EventHandler(onFadeCompleted);
    
      Storyboard.SetTarget(board, this);
    
      return board;
    }
    
    private DoubleAnimation addFadeToStoryboard(Storyboard board, 
      double fadeFrom, double fadeTo, double milliseconds)
    {
      DoubleAnimation fade = new DoubleAnimation()
      {
        Duration = new Duration(TimeSpan.FromMilliseconds(milliseconds)),
        From = fadeFrom,
        To = fadeTo,
        RepeatBehavior = new RepeatBehavior(1)
      };
    
      Storyboard.SetTargetProperty(fade,
        new PropertyPath(UIElement.OpacityProperty));
    
      board.Children.Add(fade);
    
      return fade;
    }
    

    如何使其顺序?我是否误解了故事板的基本内容?

    由于

2 个答案:

答案 0 :(得分:3)

如果故事板包含多个动画,则它们全部同时启动并同时运行。您可以将DoubleAnimations上的BeginTime属性设置为TimeSpan以指示它们应该何时开始...因此,通过传入所有先前动画的累积时间,您应该能够获得连续效果。

编辑:抱歉 - 我刚注意到了Silverlight标签。我的答案适用于WPF ...我不知道Silverlight和WPF动画之间的区别。

This可能有所帮助。它看起来像是WPF和Silverlight之间的区别。 WPF可以在同一个故事板中处理不同动画上的相同属性的动画,而Silverlight则不然。他们建议使用单个DoubleAnimationUsingKeyFrames而不是单独的DoubleAnimations ...然后每个单独的动画成为其中的关键帧,它应该在它们之间线性动画。

答案 1 :(得分:0)

我通过创建自己的音序器类来解决这个问题。它依赖于LinkedList类,因此如果要使用此代码,则必须将其与标准类交换:

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

namespace YourNamespace
{
  // An object that contains multiple storyboards, and fires off 
  // subsequent ones as they finish.

  public class StoryboardSequencer
  {
    public StoryboardSequencer()
    {
    }

    public void add(Storyboard board)
    {
      m_boards.add(board);
      board.Completed += new EventHandler(onBoardCompleted);
    }

    // Starts the storyboard from the first.
    // If already started, this call is ignored.
    public void begin()
    {
      if (m_boards.size() > 0)
      {
        m_currentBoardIndex = 0;
        beginCurrentBoard();
      }
      else
      {
        onLastBoardCompleted();
      }
    }

    // Stops and rewinds.
    // Does not call completed handler.
    public void stop()
    {
      if (m_currentBoardIndex != -1)
      {
        Storyboard board = m_boards.get(m_currentBoardIndex);
        if (board != null)
        {
          board.Stop();
        }

        m_currentBoardIndex = -1;
      }
    }

    private void beginCurrentBoard()
    {
      Storyboard board = m_boards.get(m_currentBoardIndex);
      if (board == null)
      {
        onLastBoardCompleted();
      }
      else
      {
        board.Begin();
      }
    }

    // Triggered when the sequence completes.
    public event EventHandler Completed;

    private void onBoardCompleted(object sender, EventArgs e)
    {
      m_currentBoardIndex++;

      if (m_currentBoardIndex >= m_boards.size())
      {
        onLastBoardCompleted();
      }
      else
      {
        beginCurrentBoard();
      }
    }

    private void onLastBoardCompleted()
    {
      m_currentBoardIndex = -1;
      Completed.Invoke(this, null);
    }

    private LinkedList<Storyboard> m_boards = new LinkedList<Storyboard>();

    // The current storyboard playing, or -1 if none.
    private int m_currentBoardIndex = -1;
  }
}