如何从WPF元素中删除正在运行的动画,使其完成事件不会触发?
提供的解决方案here和here删除动画的可见效果,但完成的事件在动画完成时仍会触发。
这里有一些代码可以演示我的问题(它位于带有Label,Button和TextBox的Window背后的代码中):
int _count = 0;
private void button1_Click(object sender, RoutedEventArgs e) {
myLabel.Content = "Starting animation: " + _count++;
// Cancel any already-running animations and return
// the label opacity to 1.0.
myLabel.BeginAnimation(Label.OpacityProperty, null);
myLabel.Opacity = 1.0;
// Create a new animation to fade out the label.
DoubleAnimation opacityAnim = new DoubleAnimation(1.0, 0.0, TimeSpan.FromSeconds(2), FillBehavior.Stop) {
BeginTime = TimeSpan.FromSeconds(3)
};
opacityAnim.Completed += (sndr, ev) => {
myTextbox.Text += Environment.NewLine + "Completed fired.";
};
// Start the countdown/animation.
myLabel.BeginAnimation(Label.OpacityProperty, opacityAnim);
}
如何移除动画以使其不会引发其已完成的事件?
答案 0 :(得分:3)
取消订阅已完成的事件...这也意味着您必须将已完成的事件处理程序从lambda重写为显式方法:
DoubleAnimation _opacityAnim; // Created somewhere else.
private void button1_Click(object sender, RoutedEventArgs e)
{
myLabel.Content = "Starting animation: " + _count++;
// Cancel any already-running animations and return
// the label opacity to 1.0.
_opacityAnim.Completed -= AnimationCompleted;
myLabel.BeginAnimation(Label.OpacityProperty, null);
myLabel.Opacity = 1.0;
// Create a new animation to fade out the label.
opacityAnim.Completed += AnimationCompleted;
// Start the countdown/animation.
myLabel.BeginAnimation(Label.OpacityProperty, opacityAnim);
}
private void AnimationCompleted(object sender, EventArgs e)
{
myTextbox.Text += Environment.NewLine + "Completed fired.";
}
答案 1 :(得分:0)
我遇到了同样的问题。
在我的项目中,我使用 ProgressBar 为用户提供一段时间,在此期间她/他可以取消命令。用户可以在 ProgressBar 结束之前取消命令,并在 Completed 事件的处理程序中调用实际工作代码。
可以通过调用 myProgressBar.BeginAnimation(ProgressBar.ValueProperty, null) 来移除 ProgressBar 的动画,正如您所提到的。
为了防止被移除动画的 Completed 事件的处理程序被执行,我先检查动画。每次我为 ProgressBar 创建一个 DoubleAnimation 时,我都会将它分配给一个属性。在 Completed 事件的处理程序中,我将首先检查此动画是否与存储在属性中的动画相同。如果没有,那么就返回。并且每次取消动画时,将Property 设置为null。
插图:
DoubleAnimation CurrentAnimation {get; set; }
private void DoSomeWork(){
DoubleAnimation animation = new(0D, 100D, new(TimeSpan.FromSeconds(3)));
animation.Completed += (s,e) => {
lock(lockObj) {
if(animation != CurrentAnimation)
return;
// do some work here
}
CurrentAnimation = animation;
myProgressBar.BeginAnimation(ProgressBar.ValueProperty, animation);
}
private void CancelIt(){
lock(lockObj){
myProgressBar.BeginAnimation(ProgressBar.ValueProperty, null);
CurrentProperty = null;
}
}
我认为一定有更好的方法来做到这一点,但现在这将使它按设计运行。