Wednesday, January 28, 2009

Fire and forget storyboards...

I have fallen deeply in love with Silverlight and it's evident, in Silverlight 2 at least, that one cannot do everything in XAML and there is still an element of code needed to do a job.

Because of the lack of triggers in the same sense as those that exist in WPF, Silverlight can be a pain when we need to create dynamic animated effects. However I had an idea that leans heavily upon the joys of garbage collection and anonymous methods to provide a fire-and-forget style storyboard which can do animations and handle its own events.

One little job I recently accomplished with this was to create some animation effects that had two stages; for example, to fade one element out and replace it with another.

The joy of this technique is that we can build a storyboard and the associated animation details dynamically, set it running and then just forget it while it does its thing. After the events have fired the whole thing -should- be reclaimed and garbage collected. (He said, wondering about shooting himself in the foot.

Here's some XAML...

<UserControl x:Class="FireAndForget.Page"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Width="400" Height="300">

<Grid x:Name="LayoutRoot" Background="White">

<Ellipse Fill="red"/>

<Button Content="Click Me" Width="100" Height="25" Click="Button_Click"/>

Grid>

UserControl>

And here’s the button click code..

private void Button_Click(object sender, RoutedEventArgs e)

{

Storyboard sb = new Storyboard();

DoubleAnimation da = new DoubleAnimation();

da.BeginTime = TimeSpan.FromMilliseconds(0);

da.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

da.From=1;

da.To = 0;

sb.Children.Add(da);

Storyboard.SetTargetProperty(da, new PropertyPath("(UIElement.Opacity)"));

Storyboard.SetTarget(da, this.LayoutRoot.Children[0]);

sb.Completed += delegate(Object o, EventArgs ea)

{

Random rnd=new Random();

((Ellipse)this.LayoutRoot.Children[0]).Fill = new SolidColorBrush(Color.FromArgb(255, (byte)rnd.Next(255), (byte)rnd.Next(255), (byte)rnd.Next(255)));

sb = new Storyboard();

da = new DoubleAnimation();

da.BeginTime = TimeSpan.FromMilliseconds(0);

da.Duration = new Duration(TimeSpan.FromMilliseconds(1000));

da.From=0;

da.To=1;

sb.Children.Add(da);

Storyboard.SetTargetProperty(da, new PropertyPath("(UIElement.Opacity)"));

Storyboard.SetTarget(da, this.LayoutRoot.Children[0]);

sb.Begin();

//done!

};

sb.Begin();

}

Good eh?

No comments: