【问题标题】:WPF: Prevent "Completed" event from firing after removing animationWPF:防止“已完成”事件在删除动画后触发
【发布时间】:2010-02-24 17:11:52
【问题描述】:

如何从 WPF 元素中删除正在运行的动画,使其 Completed 事件不会触发?

herehere 提出的解决方案移除了动画的可见效果,但 Completed 事件仍会在动画完成时触发。

这是一些演示我的问题的代码(它在带有标签、按钮和文本框的窗口后面的代码中):

    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);
    }

如何删除动画以使其不会引发 Completed 事件?

【问题讨论】:

    标签: wpf animation


    【解决方案1】:

    取消订阅 Completed 事件...这也意味着您必须将 Completed 事件处理程序从 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.";
     }
    

    【讨论】:

    • 令人着迷...我之前想过这个问题,但认为它仍然会触发事件,因为您立即添加了一个处理程序,并且它是同一个动画对象。但是,在实际测试它(新颖的概念)后,我发现它可以按预期工作! (您能否指出我为什么会这样的解释?)在代码中阅读有点违反直觉,但我很高兴它有效。谢谢!
    【解决方案2】:

    我遇到了同样的问题。

    在我的项目中,我使用 ProgressBar 给用户一段时间,在此期间她/他可以取消命令。用户可以在 ProgressBar 到达终点之前取消命令,并在 Completed 事件的处理程序中调用实际的工作代码。

    ProgressBar 的动画可以通过调用 myProgressBar.BeginAnimation(ProgressBar.ValueProperty, null) 来移除,就像你提到的那样。

    为了防止被移除动画的 Completed 事件的处理程序被执行,我先检查动画。每次我为 ProgressBar 创建一个 DoubleAnimation 时,我都会将它分配给一个属性。并且在 Completed 事件的处理程序中,我会首先检查这个动画是否与存储在 Property 中的动画相同。如果没有,那么就返回。并且每次我取消动画时,将 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;
      }
    }
    

    我认为必须有一些更好的方法来做到这一点,但这将使它按设计运行。

    【讨论】:

      猜你喜欢
      • 2020-12-17
      • 2012-11-16
      • 2020-05-11
      • 2012-12-17
      • 2011-09-24
      • 2012-09-24
      • 2013-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多