by
kirupa | 14 May 2008
In the
previous page,
we drilled through our XAML using C#, found the
elusive KeyTime property, and set its value
depending on what our incrementer value was. Yet,
when you ran the animation, nothing happened. What
gives?
The heading should give it away on why even though
you changed your KeyTime property's values, your
animation's speed did not change. The reason is that
properties of a running animation cannot be changed
without you restarting the animation.
That means that any
changes you make get queued, and when you
restart your animation, those changes get applied.
This means that you will need to add one more line
of code:
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);
}
sb.Begin(this);
}
To restart your
animation, you call the
Begin method on your storyboard - which is
sb in our case.
If you were to run
your application this time, notice that changing the
speed values in your combobox changes the speed of
the circle's oscillation. For this type of
animation, you are bound to see the jump where the
ball skips to its starting location whenever you
change the speed and the animation restarts.
You can work around
that generally by setting a virtual keyframe at Time 0 where
there is no keyframe that point:
[ normally, setting a virtual keyframe is a good way
to stop the jump ]
The only problem is that this type of animation
doesn't work well to virtual keyframes. There are
many other types of animations that do work well, so
you will have to experiment and figure out a way to
prevent the jumping.
There are more complicated programmatic ways of
preventing the jump, but I will save the discussion
of that topic for a later time. Your final code for
Window1.xaml.cs should be as follows:
public
partial
class
Window1
{
public
Window1()
{
this.InitializeComponent();
// Insert code
required on object creation below this
point.
}
private
void
ChangeSpeed(object
sender,
SelectionChangedEventArgs
e)
{
double
incrementer
=
1;
ComboBox
comboBox
=
sender
as
ComboBox;
ComboBoxItem
selectedItem
=
comboBox.SelectedValue
as
ComboBoxItem;
string
speed
=
selectedItem.Content.ToString();
if
(speed
==
"Slow")
{
incrementer
=
3;
}
else
if
(speed
==
"Normal")
{
incrementer
=
2;
}
else
if
(speed
==
"Fast")
{
incrementer
=
1;
}
ModifyAnimation(incrementer);
}
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);
}
sb.Begin(this);
}
}
And with that, you should be set! If you are
curious to see how my implementation turned out, you
can download the source final source files below:
Hopefully, this tutorial gave you an appreciation of
how working between XAML and C# can actually save
you a lot of time. What is nice about this is that
you take advantage of quickly creating the framework
of your animation - either manually or using a tool
such as Expression Blend, and then manipulating the
parts that you can't change easily in XAML using C#.
If you had to pick only C# or only XAML, the end
result would be more difficult to achieve. The
amount of C# code needed to, for example, define the
TranslateTransform.X on your storyboard is not easy
to figure out even with the XAML in front of you.
Being able to change the KeyTime value based on a
combobox selection change is quite difficult (if not
impossible) to do using just XAML. At the very
least, you will need to write some code to create a
ValueConverter to translate the
Slow,
Fast, and
Normal values to
the corresponding
incrementer values.
If you have any questions related to what you saw in
this tutorial or anything WPF, Silverlight, etc.,
please post in our
Programming forum.
Got a question or just want to chat? Comment below or drop by our forums (they are actually the same thing!) where a bunch of the friendliest people you'll ever run into will be happy to help you out!
When Kirupa isn’t busy writing about himself in 3rd person, he is practicing social distancing…even on his Twitter, Facebook, and LinkedIn profiles.
Hit Subscribe to get cool tips, tricks, selfies, and more personally hand-delivered to your inbox.
This is a companion discussion topic for the original entry at https://www.kirupa.com/blend_wpf/modifying_animations_pg5.htm