如何等待一个调用故事板的任务
本文关键字:故事 调用 任务 一个 何等待 等待 | 更新日期: 2023-09-27 18:05:33
我想使用故事板动画逐渐将WPF元素的可见性变为隐藏,并等待它完成后再继续执行代码。然而,我不想使用Storyboard.Completed
属性去到一个不同的函数,因为它需要一个参数传递给它,而且它会增加复杂性。
我想象它是这样工作的:
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
这是我的故事板:
<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>
我这样称呼它:
((Storyboard)FindResource("fadeOut")).Begin(item);
但是,我想等到故事板完成后再继续。
我试过了:
((Storyboard)FindResource("fadeOut")).Completed += FadeOut_Completed;
((Storyboard)FindResource("fadeOut")).Begin(item);
但是,我不能将参数item
传递给FadeOut_Completed
以将其从ListBox
中移除。
所以我试了这个:
FadeOut(item).Wait();
,
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;
}
但是卡住了。我是新的线程和异步的东西。谁能指出我哪里错了,或者建议一个替代方案?
在Completed
事件处理程序中获取项目的简单方法是使用闭包。
var storyborard = (Storyboard)FindResource("fadeOut");
storyborard.Completed += (s,e) => ListBox.Items.Remove(item);
storyborard.Begin(item);
我最近遇到了一种情况,即Completed事件没有按时触发,或者有时根本没有触发,即使我在调用Begin()之前设置了事件处理程序(这是我发现的大多数其他相关帖子的罪魁祸首)。所以我在寻找一种等待动画结束的方法,然后用同样的方法继续。我最终创建了下面的静态方法,它将您想要等待的故事板作为参数(加上您的场景的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);
}
}
我添加第二个条件是因为,在Completed事件从未触发的情况下,ClockState将始终显示为活动状态,即使在动画完成后也是如此。因此,这需要显式地设置故事板的持续时间,但到目前为止,它对我来说工作得很好。
在你的例子中,你可以像这样调用静态方法
var storyboard = (Storyboard)FindResource("fadeOut");
await RunStoryboard(storyboard, item);
// ... continue code here.