The thing to remember though is in order to have a nice looking animation, it should not lock the UI while running. If it does, you probably won't have a chance to see the animation happen!
So, here is a small sample of how to do this:
We start with our WPF window:
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center">
<Label Margin="5">Press button to start work:</Label >
<Button Name="btnStart" Width="100" Height="25" Content="Start!"
Margin="5" Click="btnStart_Click" />
<Image Name="imgWork" Source="/WPFTestApp;component/Image/working.png"
Width="40" Margin="5"></Image>
<Label Name="lblDone" Visibility="Hidden" HorizontalAlignment="Center">Done!</Label>
</StackPanel >
</Grid>
I simply added a button that starts the animation and a label that will appear once done. An image that spins will be my animating object.
Now on to the code:
We need to reference the following:
System.Windows.Media.Animation; // For the animation System.Windows.Threading; // For the threading System.ComponentModel; // For the background worker processesThere are a few ways to go around this problem, but I find that using background worker processes is the most easy and clean way to code the solution.
So, we need to initialize a background worker and instruct it what to do:
_bg = new BackgroundWorker();
_bg.DoWork += delegate(object s, DoWorkEventArgs e)
{
lblDone.Visibility = System.Windows.Visibility.Hidden;
animateButton(imgWork);
System.Threading.Thread.Sleep(5000);
};
_bg.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs e)
{
disableAnimation(imgWork);
lblDone.Visibility = System.Windows.Visibility.Visible;
};
Let's declare the animateButton and disableAnimation methods:private void animateButton(Image target)
{
if (target.Dispatcher.CheckAccess())
{
DoubleAnimation da = new DoubleAnimation
(360, 0, new Duration(TimeSpan.FromSeconds(3)));
RotateTransform rt = new RotateTransform();
target.RenderTransform = rt;
target.RenderTransformOrigin = new Point(0.5, 0.5);
da.RepeatBehavior = RepeatBehavior.Forever;
rt.BeginAnimation(RotateTransform.AngleProperty, da);
}
else
{
target.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(Action)(() =>
{
DoubleAnimation da = new DoubleAnimation
(360, 0, new Duration(TimeSpan.FromSeconds(3)));
RotateTransform rt = new RotateTransform();
target.RenderTransform = rt;
target.RenderTransformOrigin = new Point(0.5, 0.5);
da.RepeatBehavior = RepeatBehavior.Forever;
rt.BeginAnimation(RotateTransform.AngleProperty, da);
}));
}
}
private void disableAnimation(Image target)
{
if (target.Dispatcher.CheckAccess())
{
target.RenderTransform = null;
}
else
{
target.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(Action)(() =>
{
target.RenderTransform = null;
}));
}
}
I use Dispatcher.CheckAccess to ensure that the calling thread has access to the object. If not, I invoke what I need to do in a separate thread.So, all we need now is to add the code for the button:
_bg.RunWorkerAsync();to run the background worker asynchronously.
That's it!
No comments:
Post a Comment