Click here to Skip to main content
13,287,116 members (57,289 online)
Click here to Skip to main content
Add your own
alternative version


110 bookmarked
Posted 4 Jun 2010

Using Lambdas for WPF or Silverlight Animation

, 17 Jun 2010
Rate this:
Please Sign up or sign in to vote.
Shows how to use lambdas and higher-order functions for WPF/Silverlight graphics work


It’s fairly easy to create and animate a graphical primitive, say by moving it from point A to point B at constant speed. But what if you need to position several graphical objects in a particular arrangement and then animate them in a non-linear fashion? Neither Silverlight nor WPF has built-in functions for this. In this article, I’ll demonstrate ways in which one can create objects and animations dynamically using lambda-delegates and higher-order functions.

By the way, you really should check out the sample project - the animation is (IMHO) quite impressive, and is an illustration of how 2D animation can appear 3D-ish. People have been doing this for ages, of course, but I for one am surprised at how easy it is to do. 


Let us suppose that you have decided to create something like the following:

Theoretically, you could just use a for loop, but seeing how there’s a possibility of doing it in a much cleaner fashion, why not make use of it? Let’s start with something simple – a set of circles is clearly a collection, so let’s create a class that will hold references to these objects:

public class LambdaCollection<T> : Collection<T> where T : DependencyObject, new()
  public LambdaCollection(int count) { while (count --> 0) Add(new T()); }

So far we’re keeping things simple – all we’ve done is define a collection which is constrained in terms of what it contains (only objects that derive from DependencyObject and have a default constructor). We have added a constructor that makes the needed number of objects. But here comes the interesting part: we now add a method which can initialize the properties of the contained T objects using lambda expressions:

public class LambdaCollection<T> : Collection<T> where T : DependencyObject, new()
  public LambdaCollection<T> WithProperty<U>
	(DependencyProperty property, Func<int, U> generator)
    for (int i = 0; i < Count; ++i)
      this[i].SetValue(property, generator(i));
    return this;

Let’s pause and take a look at what is going on. Firstly, you’ll notice this is a fluent interface, seeing how the method ends with return this. The method itself takes two parameters. The first happens to be the property we want to change in all elements of the collection. The second is a reference to a value generator, i.e. to a function which takes the element index in the collection and returns a value of type U. This type can be anything – the only requirement is that it matches the property being set.

Attention: There is no automatic type conversion here, so if the property is of type double you cannot generate a value of type int – you’ll get an exception.

So how can we use this code? It happens to be remarkably easy. For example, to create ten circles of increasing sizes, we write the following:

var circles = new LambdaCollection<Ellipse>(10)
  .WithProperty(WidthProperty, i => 1.5 * (i+1))
  .WithProperty(HeightProperty, i => 1.5 * (i+1));

Such an expression lets us make the diameter dependent on element position. In our case, it will be 1.5 pixels for the smallest element and 15 for the largest. And, as you can see in code, one can vary width and height independently.

Well, seeing how the manipulation of X and Y co-ordinates is such a common task, we can write a useful method that will simplify things even more:

public class LambdaCollection<T> : Collection<T> where T : DependencyObject, new()
  public LambdaCollection<T> WithXY<U>(Func<int, U> xGenerator, Func<int, U> yGenerator)
    for (int i = 0; i < Count; ++i)
      this[i].SetValue(Canvas.LeftProperty, xGenerator(i));
      this[i].SetValue(Canvas.TopProperty, yGenerator(i));
    return this;

Now, let’s put it all together and create that image that we showed at the beginning of the article:

int count = 20;
var circles = new LambdaCollection<Ellipse>(count)
  .WithXY(i => 100.0 + (4.0 * i * Math.Sin(i / 4.0 * (Math.PI))),
          i => 100.0 + (4.0 * i * Math.Cos(i / 4.0 * (Math.PI))))
  .WithProperty(WidthProperty, i => 1.5 * i)
  .WithProperty(HeightProperty, i => 1.5 * i)
  .WithProperty(Shape.FillProperty, i => new SolidColorBrush(
    Color.FromArgb(255, 0, 0, (byte)(255 - (byte)(12.5 * i)))));
foreach (var circle in circles)

That’s it – using a pair of methods, one can easily create various “constellations”. Now let’s look at animation.


Linear animation using DoubleAnimation is boring. It is much more interesting when we ourselves control element values. It’s actually quite easy – by taking an existing animation class, we can redefine its animated ‘tick’ value so that it is controlled by our own generator:

public class LambdaDoubleAnimation : DoubleAnimation
  public Func<double, double> ValueGenerator { get; set; }
  protected override double GetCurrentValueCore
	(double origin, double dst, AnimationClock clock)
    return ValueGenerator(base.GetCurrentValueCore(origin, dst, clock));

Now we have a class that does linear interpolation for us, and we in turn can get a transformed value and do something with it.

Seeing how we’re working with collections, it would once again be useful to define a collection class for our purposes. Here’s such a class:

public class LambdaDoubleAnimationCollection : Collection<LambdaDoubleAnimation>
  public LambdaDoubleAnimationCollection
	(int count, Func<int, double> from, Func<int, double> to,
    Func<int, Duration> duration, Func<int, Func<double, double>> valueGenerator)
    for (int i = 0; i < count; ++i)
      var lda = new LambdaDoubleAnimation
        From = from(i), 
        To = to(i), 
        Duration = duration(i),
        ValueGenerator = valueGenerator(i)
  public void BeginApplyAnimation(UIElement [] targets, DependencyProperty property)
    for (int i = 0; i < Count; ++i)
      targets[i].BeginAnimation(property, Items[i]);

In actual fact, it is beneficial to have several constructors here (or a constructor with many optional parameters). The parameters here are value generators, i.e., these parameters can be derived from the element position in the collection. The valueGenerator parameter expects a 2nd-order function or a “function which is a function generator”, i.e., a generator which depends on the collection index and whose value depends on the interpolated double value during the animation. In the C# programming language, this implies the use of a “double lambda” such as e.g. i => j => f(j).

Here is a small example of an animation that unrolls our spiral into a sine wave:

var c = new LambdaDoubleAnimationCollection(
  i => Canvas.GetLeft(circles[i]),
  i => 10.0 * i, 
  i => new Duration(TimeSpan.FromSeconds(2)),
  i => j => 100.0 / j);
c.BeginApplyAnimation(circles.Cast<UIElement>().ToArray(), Canvas.LeftProperty);

I can’t show the animation itself, but here’s a view of the end result: 


Extending this mini-framework is easy. For example, if you want elements to be animated in sequence instead of in parallel, you can just change the LambdaDoubleAnimationCollection to the following:

public class LambdaDoubleAnimationCollection : Collection<LambdaDoubleAnimation>
  public void BeginApplyAnimation(UIElement [] targets, DependencyProperty property)
    for (int i = 0; i < Count; ++i)
      Items[i].BeginTime = new TimeSpan(0);
      targets[i].BeginAnimation(property, Items[i]);
  public void BeginSequentialAnimation(UIElement[] targets, DependencyProperty property)
    TimeSpan acc = new TimeSpan(0);
    for (int i = 0; i < Items.Count; ++i)
      Items[i].BeginTime = acc;
      acc += Items[i].Duration.TimeSpan;
    for (int i = 0; i < Count; ++i)
      targets[i].BeginAnimation(property, Items[i]);

Same goes for any other manipulation you might need. Good luck!


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Dmitri Nеstеruk
Founder ActiveMesa
United Kingdom United Kingdom
I work primarily with the .NET technology stack, and specialize in accelerated code production via code generation (static or dynamic), aspect-oriented programming, MDA, domain-specific languages and anything else that gets products out the door faster. My languages of choice are C# and F#, though I'm open to suggestions.

I'm a Microsoft MVP (Visual C#) since 2009. I run a collective tech blog at I use my own editor called TypograFix to typeset articles and blog posts.

Like the article and want this implemented in your product? Got a project that can benefit from Microsoft.Net goodness? Then get in touch!

You may also be interested in...


Comments and Discussions

GeneralMy vote of 5 Pin
manoj kumar choubey10-Apr-12 4:16
membermanoj kumar choubey10-Apr-12 4:16 
GeneralMy vote of 5 Pin
Filip D'haene7-Sep-11 12:03
memberFilip D'haene7-Sep-11 12:03 
QuestionGood job! Pin
toantvo7-Jul-11 17:58
membertoantvo7-Jul-11 17:58 
GeneralMy vote of 5 Pin
Eric Xue (brokensnow)6-Sep-10 19:12
memberEric Xue (brokensnow)6-Sep-10 19:12 
GeneralMy vote of 5 Pin
95ulisse7-Aug-10 10:15
member95ulisse7-Aug-10 10:15 
GeneralGood Pin
balavasanth27-Jul-10 21:38
memberbalavasanth27-Jul-10 21:38 
GeneralMy vote of 5 Pin
vytheese27-Jul-10 19:52
membervytheese27-Jul-10 19:52 
GeneralMy vote of 5 Pin
Diptesh_Mishra26-Jul-10 22:07
memberDiptesh_Mishra26-Jul-10 22:07 
GeneralMy vote of 5 Pin
El'Cachubrey20-Jul-10 4:43
memberEl'Cachubrey20-Jul-10 4:43 
GeneralGreat! Pin
Marcelo Ricardo de Oliveira12-Jul-10 4:31
memberMarcelo Ricardo de Oliveira12-Jul-10 4:31 
GeneralAnother great article Pin
Josh Fischer7-Jul-10 6:07
mvpJosh Fischer7-Jul-10 6:07 
GeneralRe: Another great article Pin
Dmitri Nesteruk7-Jul-10 7:51
memberDmitri Nesteruk7-Jul-10 7:51 
GeneralRe: Another great article Pin
Josh Fischer7-Jul-10 12:37
mvpJosh Fischer7-Jul-10 12:37 
Generalyou forget a variable Pin
zhushaofeng17-Jun-10 2:34
memberzhushaofeng17-Jun-10 2:34 
GeneralRe: you forget a variable Pin
Dmitri Nesteruk17-Jun-10 3:09
memberDmitri Nesteruk17-Jun-10 3:09 
GeneralVery nice work Pin
Moim Hossain17-Jun-10 2:01
memberMoim Hossain17-Jun-10 2:01 
Liked it.
Moim Hossain
R&D Project Manager
BlueCielo ECM Solutions BV

Generalvery nice Pin
zhushaofeng16-Jun-10 23:50
memberzhushaofeng16-Jun-10 23:50 
GeneralRe: very nice Pin
Dmitri Nesteruk17-Jun-10 1:21
memberDmitri Nesteruk17-Jun-10 1:21 
GeneralAwesome ... Pin
Jammer16-Jun-10 23:37
memberJammer16-Jun-10 23:37 
GeneralThanks everyone! Pin
Dmitri Nesteruk16-Jun-10 11:06
memberDmitri Nesteruk16-Jun-10 11:06 
GeneralCool! Pin
Ernest Laurentin10-Jun-10 17:54
memberErnest Laurentin10-Jun-10 17:54 
GeneralVery clever Pin
hecUngravity8-Jun-10 10:22
memberhecUngravity8-Jun-10 10:22 
GeneralCool Pin
Alan Beasley6-Jun-10 8:41
memberAlan Beasley6-Jun-10 8:41 
Generalvery very nice Pin
Sacha Barber4-Jun-10 21:39
mvpSacha Barber4-Jun-10 21:39 
GeneralGreat! Pin
UserWhoCares4-Jun-10 17:57
memberUserWhoCares4-Jun-10 17:57 
GeneralVery nice... Pin
Andrew Rissing4-Jun-10 8:37
memberAndrew Rissing4-Jun-10 8:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171207.1 | Last Updated 17 Jun 2010
Article Copyright 2010 by Dmitri Nеstеruk
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid