WPF Storyboard.Completed事件不是立竿见影的

时间:2017-11-14 11:21:42

标签: wpf

在WPF中,Storyboard可以Storyboard.SkipToFill()停止,但Completed事件不会立即触发。正如以下演示代码所示:

public partial class MainWindow : Window
{
    private Storyboard _storyboard = new Storyboard();

    public MainWindow()
    {
        InitializeComponent();
        InitializeStoryboard();
    }

    private void InitializeStoryboard()
    {
        var animation = new DoubleAnimation
        {
            Duration = TimeSpan.FromSeconds(3),
            From = 0,
            To = 300
        };

        Storyboard.SetTarget(animation, MyRectangle);
        Storyboard.SetTargetProperty(animation, new PropertyPath(WidthProperty));

        _storyboard = new Storyboard();
        _storyboard.Children.Add(animation);

        _storyboard.Completed += StoryboardOnCompleted;
    }

    private void StartButton_OnClick(object sender, RoutedEventArgs e)
    {
        _storyboard.Begin(this, true);
    }

    private void StopButton_OnClick(object sender, RoutedEventArgs e)
    {
        _storyboard.SkipToFill(this);
        Debug.WriteLine(@"SkipToFill");
    }

    private void StoryboardOnCompleted(object sender, EventArgs eventArgs)
    {
        Debug.WriteLine(@"Completed");
    }
}

点击StartButton开始Storyboard,然后点击StopButton将其停止。输出将是:

  • SkipToFill
  • 已完成

所以,我的问题:如何立即触发Completed事件?即使输出为:

  • 已完成
  • SkipToFill

2 个答案:

答案 0 :(得分:0)

您无法控制Storyboard何时引发Completed事件,但您可以在事件发生时处理该事件。

因此,您可以将另一个事件处理程序连接到Completed事件,并在引发Completed事件后执行您想要的任何操作。

这将按预期顺序打印输出,即事件处理程序将按您注册的顺序调用:

private void StopButton_OnClick(object sender, RoutedEventArgs e)
{
    _storyboard.Completed += _storyboard_Completed;
    _storyboard.SkipToFill(this);
}

private void _storyboard_Completed(object sender, EventArgs e)
{
    Debug.WriteLine(@"SkipToFill");
    _storyboard.Completed -= _storyboard_Completed;
}

private void StoryboardOnCompleted(object sender, EventArgs eventArgs)
{
    Debug.WriteLine(@"Completed");
}

如果您希望在StopButton_OnClick方法中实际阻止(异步),直到Completed被引发,您可以使用SemaphoreSlim

private readonly System.Threading.SemaphoreSlim _semaphore = new System.Threading.SemaphoreSlim(0, 1);
private async void StopButton_OnClick(object sender, RoutedEventArgs e)
{
    _storyboard.Completed += (ss, ee) => _semaphore.Release();
    _storyboard.SkipToFill(this);
    await _semaphore.WaitAsync(); //wait here...

    Debug.WriteLine(@"SkipToFill");

}

private void StoryboardOnCompleted(object sender, EventArgs eventArgs)
{
    Debug.WriteLine(@"Completed");
}

答案 1 :(得分:-1)

SkipToFill方法计划动画的结尾。我想你可以尝试等待渲染器运行(排序)。我怀疑它会起作用,但无论如何:

_storyboard.SkipToFill(this);

Dispatcher.CurrentDispatcher.Invoke(
    new Action(delegate { }), DispatcherPriority.Background);

Debug.WriteLine(@"SkipToFill");