none
WPF: Where is animation updated event?

    Question

  • Situation: Animation updates a property.

    Goal: Call my method every time, when animation updates the property.

    Problem: I can't find such an event.

    Question: Where is the event to detect every property updating done by animation?

    Code:

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.Loaded += MainWindow_Loaded;
            }
    
            Line line;
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                Canvas canvas = new Canvas();
                canvas.Background = Brushes.Black;
                this.Content = canvas;
    
                line = new Line();
                line.Stroke = Brushes.White;
                line.X1 = 0;
                line.Y1 = 0;
                line.X2 = 100;
                line.Y2 = 100;
    
                canvas.Children.Add(line);
    
                Animation();
            }
    
            private void Animation()
            {
                DoubleAnimation DB = new DoubleAnimation();
                DB.By = 100;
                DB.AutoReverse = true;
                DB.RepeatBehavior = RepeatBehavior.Forever;
                DB.Duration = new Duration(TimeSpan.FromMilliseconds(100));
    
                string name = "line";
                RegisterName(name, line);
    
                Storyboard SB = new Storyboard();
                Storyboard.SetTargetName(DB, name);
                Storyboard.SetTargetProperty(DB, new PropertyPath(Line.X2Property));
                SB.Children.Add(DB);
    
                SB.Begin(this, true);
            }
        }
    Thursday, September 3, 2015 4:42 PM

Answers

  • >>Where is the event to detect every property updating done by animation?

    There is no specific event fired when a property gets updated by an animation but you could use a DependencyPropertyDescriptor to listen to changes to the Line's X2 property:

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
          Canvas canvas = new Canvas();
          canvas.Background = Brushes.Black;
          this.Content = canvas;
    
          line = new Line();
          line.Stroke = Brushes.White;
          line.X1 = 0;
          line.Y1 = 0;
          line.X2 = 100;
          line.Y2 = 100;
    
          System.ComponentModel.DependencyPropertyDescriptor dpd = System.ComponentModel.DependencyPropertyDescriptor
            .FromProperty(Line.X2Property, typeof(Line));
          if (dpd != null) {
            dpd.AddValueChanged(line, OnX2Changed);
          }
    
    
          canvas.Children.Add(line);
    
          Animation();
        }
    
        int i;
        private void OnX2Changed(object sender, EventArgs e)
        {
          System.Diagnostics.Debug.WriteLine(i++);
        }
    

    Note however that the property value changes multiple times during one single animation. You could of course check the value of the property if you want to do something when the animated property has a certain value:

        private void OnX2Changed(object sender, EventArgs e)
        {
          if((int)line.X2 == 100)
            System.Diagnostics.Debug.WriteLine(line.X2);
        }

    If you want to something when the animation has finished you should handle the Completed event of the Storyboard but then you cannot set the RepeatBehavior to Forever since this effectively means that the Storyboard will never be completed:

        private void Animation()
        {
          DoubleAnimation DB = new DoubleAnimation();
          DB.By = 100;
          DB.AutoReverse = true;
          //DB.RepeatBehavior = RepeatBehavior.Forever;
          DB.Duration = new Duration(TimeSpan.FromMilliseconds(100));
    
          string name = "line";
          RegisterName(name, line);
    
          Storyboard SB = new Storyboard();
          Storyboard.SetTargetName(DB, name);
          Storyboard.SetTargetProperty(DB, new PropertyPath(Line.X2Property));
          SB.Children.Add(DB);
          SB.Completed += SB_Completed;
    
          SB.Begin(this, true);
        }
    
        void SB_Completed(object sender, EventArgs e)
        {
          //do something
        }
    

    These are pretty much your options.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then please start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Marked as answer by Ziya Ceferov Friday, September 4, 2015 3:12 PM
    Friday, September 4, 2015 8:46 AM

All replies

  • There isn't such an event.

    The storyboard has a completed event as I showed you in an earlier thread:

    Storyboard sb = new Storyboard();
    sb.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 100));
    sb.Completed += delegate
    {
         // Do stuff
    };
    sb.Begin();

    You can only animate dependency properties though.

    And dependency properties have the callback mechanism which you can subscribe a method to.

    So you could possibly override the metadata on the target property and provide your own callback.

    You can use overridemetadata

    https://msdn.microsoft.com/en-us/library/ms597491%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

    For example:

    http://stackoverflow.com/questions/1310090/how-can-i-add-logic-to-an-existing-dependency-property-callback

    UIElement.RenderTransformOriginProperty.OverrideMetadata(typeof(foo), 
    new PropertyMetadata(new PropertyChangedCallback(Origin_Changed)));

    The property change callback is specified in PropertyMetadata and that code there will mean a method is called when the dp changes.

    .

    Subclassing line might be the most convenient way to go there.


    Thursday, September 3, 2015 6:00 PM
    Moderator
  • >>Where is the event to detect every property updating done by animation?

    There is no specific event fired when a property gets updated by an animation but you could use a DependencyPropertyDescriptor to listen to changes to the Line's X2 property:

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
          Canvas canvas = new Canvas();
          canvas.Background = Brushes.Black;
          this.Content = canvas;
    
          line = new Line();
          line.Stroke = Brushes.White;
          line.X1 = 0;
          line.Y1 = 0;
          line.X2 = 100;
          line.Y2 = 100;
    
          System.ComponentModel.DependencyPropertyDescriptor dpd = System.ComponentModel.DependencyPropertyDescriptor
            .FromProperty(Line.X2Property, typeof(Line));
          if (dpd != null) {
            dpd.AddValueChanged(line, OnX2Changed);
          }
    
    
          canvas.Children.Add(line);
    
          Animation();
        }
    
        int i;
        private void OnX2Changed(object sender, EventArgs e)
        {
          System.Diagnostics.Debug.WriteLine(i++);
        }
    

    Note however that the property value changes multiple times during one single animation. You could of course check the value of the property if you want to do something when the animated property has a certain value:

        private void OnX2Changed(object sender, EventArgs e)
        {
          if((int)line.X2 == 100)
            System.Diagnostics.Debug.WriteLine(line.X2);
        }

    If you want to something when the animation has finished you should handle the Completed event of the Storyboard but then you cannot set the RepeatBehavior to Forever since this effectively means that the Storyboard will never be completed:

        private void Animation()
        {
          DoubleAnimation DB = new DoubleAnimation();
          DB.By = 100;
          DB.AutoReverse = true;
          //DB.RepeatBehavior = RepeatBehavior.Forever;
          DB.Duration = new Duration(TimeSpan.FromMilliseconds(100));
    
          string name = "line";
          RegisterName(name, line);
    
          Storyboard SB = new Storyboard();
          Storyboard.SetTargetName(DB, name);
          Storyboard.SetTargetProperty(DB, new PropertyPath(Line.X2Property));
          SB.Children.Add(DB);
          SB.Completed += SB_Completed;
    
          SB.Begin(this, true);
        }
    
        void SB_Completed(object sender, EventArgs e)
        {
          //do something
        }
    

    These are pretty much your options.

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then please start a new thread if you have a new question. Please don't ask several questions in the same thread.

    • Marked as answer by Ziya Ceferov Friday, September 4, 2015 3:12 PM
    Friday, September 4, 2015 8:46 AM