程序中控制storyboard【wpf 动画控制】
1. How to trigger a storyboard from code that was created in Blend.
Let's say we have an animation in Blend to do an opacity fade on an image. Assuming it was created by creating a new timeline and leave the "Create as a resource" checkbox checked, we can get at it from code pretty easily.Simply grab the storyboard from the resources, cast it appropriately and begin it.
Storyboard s = (Storyboard) this.FindResource("FadeIn");
this.BeginStoryboard(s);
Now, the reason this works is that the storyboard itself contains information about the name of the object that it wants to animate. If you look at the storyboard in the sample code I posted, it sets the Storyboard.TargetName value explicitly to the name "image". Thus, when the storyboard is called from the page itself via BeginStoryboard, it is able to find the element named image and run the animations. But what happens if we want to generically apply that animation that was created in Blend to other elements?
2. How to trigger a storyboard from code and apply it to another UI element
Well, to accomplish this task, we need to start hacking XAML. If this scares you, don't read on. But the fact is that XAML generated from Blend sometimes needs a little love. So, in this case, we are going to copy that storyboard. We can't do that without jumping into the XAML and manually coping the entire <Storyboard> and giving it a new x:Key. Once we've done that, we have manually remove every instance where Storyboard.TargetName is set. Literally, remove the entire attribute. Now, we can apply this storyboard to any UIElement and not just images. In this case, we call the Begin method from the storyboard itself, passing the element we want the storyboard to be applied to.
Storyboard s = (Storyboard)this.FindResource("FadeIn2");
s.Begin(textBlock);
The thing to watch out for with this technique is to make sure you call the storyboard on an element that in fact has all the properties referenced in the storyboard. Otherwise, you'll get a runtime exception that says something like:
Additional information: '[Unknown]' property does not point to a DependencyObject in path '(0).(1).[0].(2)'.
Which is saying that the animation could find the property that it was told to animate. A place where this can get you is if you are doing any Transform animations, such as Scale, Translate, Rotate or Skew. By default, when you add an element to Blend, it does not create a TransformGroup for it. For example, go to Blend, add a Rectangle to the stage and see what it creates in XAML. It won't have a RenderTransform. Now, go change its scale to 2 and then change it back to 1. Now look at its XAML: a RenderTransform has been permanently added to it as a child which doesn't do anything! Blend counts on that TransformGroup for doing its animations, in that exact order (Scale, Skew, Rotate, Translate). So, if you've created an animation that does a transform and you want to apply it to some other element, be sure that the element has a TransformGroup with the four transforms.
3. How to tweak an animation created in Blend on the fly in code
Let's say there's an animation created in Blend that you want to use, but you want to actually modify it with some dynamic values at runtime, maybe adding more animation. First, you grab the storyboard and clone it so you have a new instance to party on. Then, you create your animation in code -- that's where you could insert dynamic variables. Finally, you have to create a property path to the value you want animated. The syntax is a little goofy, but once you crack its code as far as a path (good doc here) you'll be off and running. Here's the code I used to add a scale animation on the fly:
Storyboard s = ((Storyboard)this.FindResource("FadeIn2")).Clone();
DoubleAnimation da = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(1), FillBehavior.HoldEnd);
Storyboard.SetTargetProperty(da, new PropertyPath("(0).(1).[0].(2)", UIElement.RenderTransformProperty,
TransformGroup.ChildrenProperty,
ScaleTransform.ScaleXProperty));
s.Children.Add(da);
s.Begin(rectangle);
You could use a similar technique to crack into the storyboard, grab an animation that was created in XAML and tweak it. So for example, we could grab the animation from the storyboard and change its begin time like this:
DoubleAnimationUsingKeyFrames d = (DoubleAnimationUsingKeyFrames)s.Children[0];
d.BeginTime = TimeSpan.FromSeconds(.5);
4. How to crack into an animation that is part of a DataTemplate
Doh! You can't! I tried every workaround I could, but once a ContentTemplate gets loaded, it is in the WPF terminology "Sealed" and I've never seen a way to make it unsealed, even before it is added to the visual tree. Bummer.

浙公网安备 33010602011771号