我想使用故事板动画逐渐将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;
}
但是那个卡住了。我是线程和异步的新手。有人可以指出我出错的地方或提出替代方案吗?
答案 0 :(得分:2)
在Completed
事件处理程序中获取项目的一种简单方法是使用闭包。
var storyborard = (Storyboard)FindResource("fadeOut");
storyborard.Completed += (s,e) => ListBox.Items.Remove(item);
storyborard.Begin(item);
答案 1 :(得分:1)
我最近遇到了一个情况,即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);
}
}
我添加了第二个条件,因为在完成事件永远不会触发的情况下,即使在动画结束后,ClockState也始终显示为活动状态。因此,这需要明确设置故事板的持续时间,但到目前为止它一直很适合我。
所以在你的情况下,你只需要调用静态方法。
var storyboard = (Storyboard)FindResource("fadeOut");
await RunStoryboard(storyboard, item);
// ... continue code here.