How to get ObjectAnimationUsingKeyFrames to work programmatically

Hi everyone... For learning purposes I'm playing around with animation. One thing I can't get for the life of me to work is ObjectAnimationUsingKeyFrames. This should be relatively simple so I'm probably missing something.

In the following code I'm simply trying to make a Storyboard that hides an "element" (which can be any FrameworkElement) after one second by updating its Visibility property. However it will not work. Any idea what I'm doing wrong I've only seen examples of keyframes in XAML but I believe I'm doing the same sort of things as all those.

Help is appreciated!

---

// Create the storyboard
Storyboard storyboard = new Storyboard();

// Add keyframe to turn off from element visibility
ObjectAnimationUsingKeyFrames kf = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(kf, new PropertyPath(FrameworkElement.VisibilityProperty));
kf.Duration = TimeSpan.FromSeconds(1);
kf.FillBehavior = FillBehavior.Stop;
kf.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, KeyTime.FromPercent(1)));
storyboard.Children.Add(kf);

// Start the storyboard
storyboard.Begin(element);




Answer this question

How to get ObjectAnimationUsingKeyFrames to work programmatically

  • cwlaualex

    Ok sounds good... it would be nice if Storyboard had an OnCompleted method in addition to the existing Completed event. I'd like to create a class that inherits Storyboard and perform my cleanup in OnCompleted. I can use the Completed event for now though.

  • Raoul_BennetH

    One thing you can do is to set the underlying property to the value you wish to persist after the storyboard to the final value. So, here, you could set element.Visibility to Visbility.Collapsed and then create a Keyframe at 0 equal to the old value of the Visibility value. Since both starting the animation and the visibility change would happen "simultaneously", nothing would appear to change, but when the storyboard stops (or is removed), the local value would take effect again, which would be Collapsed.

    -Adam Smith [MS]



  • Vaassu

    Ok, I figured out my own answer after playing around some more. FillBehavior.Stop seems to make the value reset to its pre-animation value. And since I had my keyframe at the end of the animation, it made its change and changed it back right away.

    So if I take that out I run into a new problem. FillBehavior is switched to HoldEnd (the default value). If that is set I do get the proper behavior where the element hides after a second. But the problem is that I can no longer set the Visibility property of the element directly in code. Other animations can modify it though. So it seems like the storyboard is still attached and is in some animating state. Do I need to remove the storyboard or animation somehow when it's done and what's the best way to do this



  • Macinkross

    Right - Stop behavior, or remove the storboard entirely. The standard pattern is to register a callback with the Completed event which removes the storyboard, thus "freeing" the local values from animation override.

    -Adam Smith [MS]



  • sohaibi

    Thanks, that seems to work. And I assume your recommendation would work only with the Stop fill behavior, correct

    Out of curiosity, since HoldEnd fill behavior seems to be forcing the end value to stick with the control and will not allow the value to be changed by setting the property directly, how would I remove that "hold" or "freeze" if I did want to be able to switch the property value via code again



  • SimonJohns

    Adam Smith MS wrote:

    Right - Stop behavior, or remove the storboard entirely. The standard pattern is to register a callback with the Completed event which removes the storyboard, thus "freeing" the local values from animation override.

    Arrgg... still can't get it to work with HoldEnd functionality. Please try this simple test. I have a Button on a window and when clicked, it will start a storyboard of a second long. Halfway through it hides itself. Then at the end of the storyboard, it should make itself visible again via code. I'm attaching to the Completed event but the button still is being animated as I can see from my console printout message.

    Here is the code:

    ---
    private void button_Click(object sender, EventArgs e) {
    Console.WriteLine("BEFORE: " + button.Visibility + " : " + button.HasAnimatedProperties);

    // Create the storyboard
    Storyboard storyboard = new Storyboard();
    storyboard.Completed += new EventHandler(storyboard_Completed);

    // Add keyframe to turn off from button visibility
    ObjectAnimationUsingKeyFrames kf = new ObjectAnimationUsingKeyFrames();
    Storyboard.SetTargetProperty(kf, new PropertyPath(FrameworkElement.VisibilityProperty));
    kf.Duration = TimeSpan.FromSeconds(1);
    kf.KeyFrames.Add(new DiscreteObjectKeyFrame(Visibility.Collapsed, KeyTime.FromPercent(.5)));
    storyboard.Children.Add(kf);

    // Start the storyboard
    storyboard.Begin(button);
    }

    void storyboard_Completed(object sender, EventArgs e) {
    button.Visibility = Visibility.Visible;
    Console.WriteLine("COMPLETE: " + button.Visibility + " : " + button.HasAnimatedProperties);
    }
    ---

    And when I run the window and click the button I get these messages:

    BEFORE: Visible : False
    COMPLETE: Collapsed : True

    Based on what you said I woudl expect the messages to be these instead:

    BEFORE: Visible : False
    COMPLETE: Visible : False

    Any ideas



  • Itzik Katzav

    Ah, sorry - registering with the Completed event isn't sufficient. What I meant to suggest was that you consider registering a callback with the Completed event, and to then Remove the storyboard in the callback.

    For example (from yours above):

    // Create the storyboard
    Storyboard storyboard = new Storyboard();
    storyboard.Completed += delegate(object sender, EventArgs e)
    {
    button.Visibility = Visibility.Visible;
    storyboard.Remove(button);
    };

    -Adam Smith [MS]



  • How to get ObjectAnimationUsingKeyFrames to work programmatically