简体   繁体   English

如何等待调用故事板的任务

[英]How to await a Task that calls a storyboard

I want to use a storyboard animation to gradually turn a WPF element's visibility to hidden, and wait for it to complete before proceeding in the code. 我想使用故事板动画逐渐将WPF元素的可见性转换为隐藏,并在继续执行代码之前等待它完成。 However, I don't want to use a Storyboard.Completed property to go to a different function because it would require a parameter passed to it, plus it would increase the complexity. 但是,我不想使用Storyboard.Completed属性转到不同的函数,因为它需要传递给它的参数,而且会增加复杂性。

I imagine it working like so: 我想它的工作原理如下:

ListBoxItem itemToRemove = sender as ListBoxItem;    
FadeOut(itemToRemove);      // this needs to wait until animation is completed
ListBox.Items.Remove(item); // because this line will remove it immediately

This is my storyboard: 这是我的故事板:

    <Storyboard x:Key="fadeOut">
        <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0">
                <DiscreteObjectKeyFrame.Value>
                    <Visibility>Visible</Visibility>
                </DiscreteObjectKeyFrame.Value>
            </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
        <DoubleAnimation BeginTime="0:0:0.0" Duration="0:0:0.5" From="1" Storyboard.TargetProperty="Opacity" To="0" />
    </Storyboard>

And I call it like so: 我称之为:

((Storyboard)FindResource("fadeOut")).Begin(item);

However, I want to wait until the storyboard completes before proceeding. 但是,我想等到故事板完成后再继续。

I tried this: 我试过这个:

((Storyboard)FindResource("fadeOut")).Completed += FadeOut_Completed;
((Storyboard)FindResource("fadeOut")).Begin(item);

However, I couldn't pass the parameter item to FadeOut_Completed to remove it from the ListBox . 但是,我无法将参数item传递给FadeOut_Completed以将其从ListBox删除。

So I tried this: 所以我尝试了这个:

 FadeOut(item).Wait();

Where 哪里

 public Task FadeOut(ListBoxItem item)
 {
      var tcs = new TaskCompletionSource<bool>();
      ((Storyboard)FindResource("fadeOut")).Begin(item);
      ((Storyboard)FindResource("fadeOut")).Completed += (s, e) => tcs.SetResult(true);
      return tcs.Task;
 }

But that got stuck. 但那个卡住了。 I'm new to threading and async stuff. 我是线程和异步的新手。 Could someone point out where I'm going wrong or suggest an alternative? 有人可以指出我出错的地方或提出替代方案吗?

Just a simple way to get item in Completed event handler is using closure. Completed事件处理程序中获取项目的一种简单方法是使用闭包。

var storyborard = (Storyboard)FindResource("fadeOut");
storyborard.Completed += (s,e) => ListBox.Items.Remove(item);
storyborard.Begin(item);

I recently ran into a situation where the Completed event wasn't firing on time, or sometimes not firing at all, even if I set the event handler prior to calling Begin() (that was the culprit on most other related posts I found). 我最近遇到了一个情况,即Completed事件没有按时触发,或者有时根本没有触发,即使我在调用Begin()之前设置事件处理程序(这是我找到的大多数其他相关帖子的罪魁祸首) 。 So I was looking for a way to wait for the animation to end, then continue on in the same method. 所以我一直在寻找一种等待动画结束的方法,然后继续使用相同的方法。 I ended up creating the below static method that takes the storyboard you want to await as the parameter (plus a FrameworkElement for your scenario). 我最终创建了下面的静态方法,该方法将您想要的故事板作为参数(加上您的方案的FrameworkElement)。

public async static Task RunStoryboard(Storyboard Story, FrameworkElement item)
{
    Story.Begin(item);
    while (Story.GetCurrentState() == ClockState.Active && Story.GetCurrentTime() < Story.Duration)
    {
        await Task.Delay(100);
    }
}

I added the second condition because, during those situations where the Completed event never fired, the ClockState would always appear as active, even after the animation finished. 我添加了第二个条件,因为在Completed事件永远不会触发的情况下,即使在动画结束后,ClockState也总是显示为活动状态。 As such, this requires setting the Storyboard's duration explicitly, but it's been working well for me so far. 因此,这需要明确设置Storyboard的持续时间,但到目前为止它一直很适合我。

So in your case, you would just call the static method like so. 所以在你的情况下,你只需要调用静态方法。

var storyboard = (Storyboard)FindResource("fadeOut");
await RunStoryboard(storyboard, item);
// ... continue code here.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM