开发者

How can I make a storyboard fade in, pause, and then fade out (through code)?

开发者 https://www.devze.com 2023-03-23 22:39 出处:网络
I wrote the following code. It tries to create a storyboard that does the following: fade in for 500ms

I wrote the following code. It tries to create a storyboard that does the following:

  1. fade in for 500ms
  2. pause for 1000ms
  3. fade out for 500ms

But at run time get an System.InvalidOperationException followed by the following output:

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

This seems to suggest its trying to do all the animations at once rather than sequentially.

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;
}

How can I make it sequential? Am I misinterpreting something fund开发者_开发技巧amental about storyboards?

Thanks


If the storyboard contains multiple animations they all get started at the same time and run simultaneously. You can set the BeginTime property on the DoubleAnimations to a TimeSpan to indicate when they should begin...so by passing in an accumulative time of all the previous animations you should be able to get the sequential effect.

EDIT: Sorry - I just noticed the Silverlight tag. My answer works in WPF...I don't know about the differences between Silverlight and WPF animations.

This might help. It looks like it is a difference between WPF and Silverlight. Where WPF can handle animating the same property on different animations in the same storyboard, Silverlight doesn't. Instead of having separate DoubleAnimations they suggest using a single DoubleAnimationUsingKeyFrames...then each of your separate animations becomes a key frame within it and it should animate linearly between them.


I've solved this by creating my own sequencer class. It has a dependency on a LinkedList class, so you'll have to swap that out with the standard one if you want to use this code:

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;
  }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消