by
kirupa | 14 May 2008
We are almost there! In
the
previous page, we started to add some code, and
I provided and explained the code needed to get the
selected value from our combo box. We left
everything at a bit of a cliffhanger with this
mysterious call being made to a nonexistent
ModifyAnimation method. Let's pick up from there!
Now that we
have our combo box setup, let's figure out how to
change the value of each of our keyframes' KeyTime
value. First, because I am sure it is bugging you,
add the following new method called ModifyAnimation
that takes a double as its argument:
- private
void
ModifyAnimation(double
incrementer)
- {
-
- }
If you recall, the
ChangeSpeed method calls ModifyAnimation with our
incrementer value as the argument. We just created
that method above. If you run your application,
nothing noticeable will happen when you change the
selected values in your combo box.
What we are going to
do now is alter the KeyTime values stores in each of
our keyframes. Here is the game plan. We have no way
of directly targeting the keyframes. What we have to
do is first get a reference to our Storyboard, then
get a reference to the Animation, and then get to
the Keyframes!
Because this will
require us traversing through our Storyboard, for
reference, below is the XAML for our animation:
- <Storyboard
x:Key="Oscillate">
- <DoubleAnimationUsingKeyFrames
-
BeginTime="00:00:00"
-
RepeatBehavior="Forever"
-
Storyboard.TargetName="ellipse"
-
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.X)">
-
-
- <SplineDoubleKeyFrame
-
KeySpline="1,0,1,1"
-
KeyTime="00:00:00"
- Value="0"/>
- <SplineDoubleKeyFrame
-
KeySpline="0,1,1,1"
-
KeyTime="00:00:01"
- Value="-130"/>
- <SplineDoubleKeyFrame
-
KeySpline="1,0,1,1"
-
KeyTime="00:00:02"
- Value="0"/>
- <SplineDoubleKeyFrame
-
KeySpline="0,1,1,1"
-
KeyTime="00:00:03"
- Value="140"/>
- <SplineDoubleKeyFrame
-
KeySpline="1,0,1,1"
-
KeyTime="00:00:04"
- Value="0"/>
-
- </DoubleAnimationUsingKeyFrames>
- </Storyboard>
Let's start adding
some code. First, let's get a reference to our
Storyboard:
-
private
void
ModifyAnimation(double
incrementer)
-
{
- Storyboard
sb
=
this.FindResource("Oscillate")
as
Storyboard;
-
}
Because our Storyboard
is stored as a Resource, I use the
FindResource
method and pass in the key of our storyboard, which
is Oscillate. Because FindResource returns values
only as the object
type, I cast it as a Storyboard by using the VB-like
as Storyboard
syntax.
Next up is the code
for getting the reference to our animation:
-
private
void
ModifyAnimation(double
incrementer)
-
{
-
Storyboard
sb
=
this.FindResource("Oscillate")
as
Storyboard;
-
DoubleAnimationUsingKeyFrames
animation
=
sb.Children[0]
as
DoubleAnimationUsingKeyFrames;
-
}
Your storyboard stores
children that are animations. In our
case, our storyboard has just one child - the
DoubleAnimationUsingKeyframes. Therefore, I
pass in the index position of 0 to the Children
collection of our storyboard and cast the resulting
value as that of our DoubleAnimationUsingKeyframes
object.
The thing to note is
that I would not know all of this unless I looked at
the XAML. Depending on your animation, your
animation
could be a host of different types besides
DoubleAnimationUsingKeyframes. Because I have the
XAML directly in front of me, I can feel safe
declaring a new object of type
DoubleAnimationUsingKeyframes and deliberately
retrieving the first item from our storyboard's
Children collection without taking edge cases into
account. If I were to modify my animation such that
these assumptions no longer hold true, then I would
have to make sure I update this code as well.
Our animation has
keyframes, so what we are going to do next is figure
out a way to gain access to them:
-
private
void
ModifyAnimation(double
incrementer)
-
{
-
Storyboard
sb
=
this.FindResource("Oscillate")
as
Storyboard;
-
DoubleAnimationUsingKeyFrames
animation
=
sb.Children[0]
as
DoubleAnimationUsingKeyFrames;
-
DoubleKeyFrameCollection
keyFrames
=
animation.KeyFrames;
-
}
Unlike before were we
call the Children property of a collection, your
animation doesn't store the Keyframes as children.
Instead, the keyframes are stored in their own
KeyFrames property, and you can access them by
calling your animation's KeyFrames property as shown
above.
Your
keyFrames object
now stores a collection of keyframes that you can
iterate through, so let's add a
for loop:
-
private
void
ModifyAnimation(double
incrementer)
-
{
-
Storyboard
sb
=
this.FindResource("Oscillate")
as
Storyboard;
-
DoubleAnimationUsingKeyFrames
animation
=
sb.Children[0]
as
DoubleAnimationUsingKeyFrames;
-
DoubleKeyFrameCollection
keyFrames
=
animation.KeyFrames;
- for
(int
i
=
0;
i
<
keyFrames.Count;
i++)
- {
-
SplineDoubleKeyFrame
keyFrame
=
keyFrames[i]
as
SplineDoubleKeyFrame;
- keyFrame.KeyTime
=
new
TimeSpan(0,
0,
(int)incrementer
*
i);
- }
-
}
Because we have five
keyframes,
keyFrames.Count will return 5. What we do in
each of those five iterations is first, get the
keyFrame and cast it as a
SplineDoubleKeyFrame, and second, set the
KeyTime to a new
TimeSpan whose second value is our loop's index
position i multiplied by the
incrementer value
we pass in.
After you have
finished adding the above line of code, you are
pretty much done. If you hit F5 and run your
application, your animation will start playing. Each
time you change the speed value in your combobox,
does the animation's speed actually change? No, the
speed does not, and let's find out why and how to
fix this on the
next page.
Onwards to the
next page!
|