Click here to Skip to main content
Click here to Skip to main content

Stick Figure Animation Using C# and WPF

, 14 Oct 2010
Rate this:
Please Sign up or sign in to vote.
Discover how to create complex stick figure animations using simple WPF or Silverlight elements.

StickFigure

Table of Contents

Introduction

Recently I wanted to create a kind of stick figure animation in WPF or Silverlight, but I found no material on the issue. I got frustrated and then decided to do something myself, and fortunately I was successful. This article describes, in some detail, how to create a stick figure animation in WPF, although I'm sure it could be easily ported to Silverlight. This article is intended to share some nice discoveries with the readers.

System Requirements

If you already have Visual Studio 2008 or Visual Studio 2010, that's enough to run the application. If you don't, you can download the following 100% free development tool directly from Microsoft:

Background

For some time, I wondered how to create a pivot stick animation using WPF or Silverlight. In the first attempt, I used sticks that moved independently on a canvas surface. But instead of using the standard WPF Animation classes, I had to control the animation all by myself, using timers to update both the angle and the positions of each individual stick, and also taking rotation speed into consideration. Since a stick figure is an articulated system, when one member is rotated, the dependent members must be rotated accordingly. For example, if I rotated a leg, I also had to rotate the foreleg accordingly, as well as re-calculate the foreleg coordinates based on the new position of the knee. And this was really a cumbersome task to do.

After struggling a lot with the code, in the end, it worked well, but realized that I ended up creating a little monster, a real code horror, and then decided to throw it away and start over from scratch.

The idea is that, in any articulated body, I can choose one particular segment of that body as the "root" for the whole body, and then "link" pieces successively at the edges of the first segment, creating a chain of segments. The good news is that it can be accomplished in WPF (or Silverlight if you wish) by creating a Grid element to represent each individual segment, and adding other Grid elements as child elements of the root segment. The Grid element is the most powerful visual element, and it's not without reason. The magic is done by creating three ColumnDefinitions inside the Grid: one ColumnDefinition residing in the middle of the segment and determines the extension of the segment, while the other two staying at the edges and acting as pivot joints for the child segments.

The Base Segment

The Base Segment

BaseSegment is the abstract class from which we derive the other segment classes. Notice that it does not have any appearance. Instead, it only defines the three grid columns as seen in the figure above.

protected virtual void InitializeSegment()
{
    this.ShowGridLines = false;
    this.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
    this.ColumnDefinitions.Add(new ColumnDefinition() { 
              Width = GridLength.Auto, MinWidth = segmentWidth  });
    this.ColumnDefinitions.Add(new ColumnDefinition() { 
              Width = new GridLength(segmentLength) });
    this.ColumnDefinitions.Add(new ColumnDefinition() { 
              Width = GridLength.Auto, MinWidth = segmentWidth  });

    st = new ScaleTransform()
    {
    };

    tt = new TranslateTransform()
    {
        X = 0,
        Y = 0
    };

    rt = new RotateTransform()
    {
        CenterX = segmentWidth,
        CenterY = segmentWidth
    };

    TransformGroup tGroup = new TransformGroup();

    tGroup.Children.Add(st);
    tGroup.Children.Add(rt);
    tGroup.Children.Add(tt);
    this.RenderTransform = tGroup;
}

The Circle Segment

The Circle Segment

The Circle Segment is used only in the Head of the stick figure. The circle is positioned at the central column, and the two corners at the edge are used as pivot points:

protected override void InitializeSkin()
{
    this.ColumnDefinitions[1].Width = new GridLength(segmentLength * 2);
    this.Height = segmentLength * 2;

    Rectangle rect = new Rectangle()
    {
        Stroke = new SolidColorBrush(Colors.White),
        StrokeThickness = 0.5,
        HorizontalAlignment = HorizontalAlignment.Stretch,
        VerticalAlignment = VerticalAlignment.Stretch,
        RadiusX = segmentWidth * 2,
        RadiusY = segmentWidth * 2
    };
    rect.SetValue(Grid.ColumnProperty, 1);
    rect.SetValue(Panel.ZIndexProperty, 1);

    this.Children.Add(rect);
}

The Axis Segment

The Axis Segment

The AxisSegment is used in almost every part in our stick figure. The code below shows that the "skin" of the axis segment is defined by a round-cornered rectangle that spans over the three columns of the BaseSegment element.

protected override void InitializeSkin()
{
    rect = new Rectangle()
    {
        Stroke = new SolidColorBrush(Colors.White),
        StrokeThickness = 0.5,
        Width = segmentLength * 2,
        MaxWidth = segmentLength * 2,
        Height = segmentWidth * 2,
        RadiusX = segmentWidth,
        RadiusY = segmentWidth,
        HorizontalAlignment = HorizontalAlignment.Left,
        VerticalAlignment = VerticalAlignment.Stretch,
        Margin = new Thickness(0, 0, 0, 0)
    };

    rect.SetValue(Grid.ColumnProperty, 0);
    rect.SetValue(Grid.ColumnSpanProperty, 3);
    
    Rectangle dash1 = new Rectangle()
    {
        Stroke = new SolidColorBrush(Colors.Red),
        StrokeDashArray = new DoubleCollection(new double[]{4,4}),
        StrokeThickness = 1,
        Width = 1,
        HorizontalAlignment = HorizontalAlignment.Left,
        VerticalAlignment = VerticalAlignment.Stretch
    };

    Rectangle dash2 = new Rectangle()
    {
        Stroke = new SolidColorBrush(Colors.Green),
        StrokeDashArray = 
          new DoubleCollection(new double[] { 2, 2 }.ToList()),
        StrokeThickness = 1,
        Width = 1,
        HorizontalAlignment = HorizontalAlignment.Right,
        VerticalAlignment = VerticalAlignment.Stretch
    };

    dash1.SetValue(Grid.ColumnProperty, 1);
    dash2.SetValue(Grid.ColumnProperty, 1);

    this.Children.Add(dash1);
    this.Children.Add(dash2);

    this.Children.Add(rect);
}

Building Mr. StickMan: Head and Trunk

Head And Trunk

The Head is the first part in the stick figure. Then the Trunk is added as a child, positioned at the third column of the Head segment. Notice that, since the columns are positioned horizontally, we have to rotate the head 90 degrees so that the body can stand vertically. The head has a length of 10, while the Trunk has a length of 20. The Trunk is attached to PivotPoint P2 of the Head, that is, at the bottom of the Head segment:

private void CreateStickFigure()
{
    ...

    head = new CircleSegment(10);
    head.TT.X = currentPoint.X;
    head.TT.Y = currentPoint.Y;
    head.RT.Angle = 90;
    head.VerticalAlignment = VerticalAlignment.Top;
    head.HorizontalAlignment = HorizontalAlignment.Left;

    trunk = new AxisSegment(20);

    ...

    head.AddChildElement(trunk, PivotPoint.P2, Layer.ForeGround);

    ...

    this.Children.Add(head);
}

Head, Trunk, and Arms

Head, Trunk And Arms

The arms must be positioned at the shoulder point of the stick figure; that is, the arms are children of the Trunk segment and positioned at the PivotPoint P1, that is, the first column of the grid, at the top of the Trunk.

private void CreateStickFigure()
{
    ...

    head = new CircleSegment(10);
    head.TT.X = currentPoint.X;
    head.TT.Y = currentPoint.Y;
    head.RT.Angle = 90;
    head.VerticalAlignment = VerticalAlignment.Top;
    head.HorizontalAlignment = HorizontalAlignment.Left;

    trunk = new AxisSegment(20);

    ...
    
    arm1 = new AxisSegment(12);
    arm2 = new AxisSegment(12);
    
    ...

    trunk.AddChildElement(arm1, PivotPoint.P1, Layer.BackGround);
    trunk.AddChildElement(arm2, PivotPoint.P1, Layer.ForeGround);

    head.AddChildElement(trunk, PivotPoint.P2, Layer.ForeGround);

    ...

    this.Children.Add(head);
}

The Whole Body

The Whole Body

Now we have all the body segments. The segment hierarchy is defined by the tree list below:

  • Head
    • Trunk
      • Left Arm
        • Left Forearm
      • Right Arm
        • Right Forearm
      • Left Leg
        • Left Foreleg
      • Right Leg
        • Right Foreleg

Here is the code for building all parts of the body of Mr. StickMan:

private void CreateStickFigure()
{
    ...

    head = new CircleSegment(10);
    head.TT.X = currentPoint.X;
    head.TT.Y = currentPoint.Y;
    head.RT.Angle = 90;
    head.VerticalAlignment = VerticalAlignment.Top;
    head.HorizontalAlignment = HorizontalAlignment.Left;

    trunk = new AxisSegment(20);

    leg1 = new AxisSegment(15);
    leg1.Margin = new Thickness(5, 0, 0, 0);

    leg2 = new AxisSegment(15);
    leg2.Margin = new Thickness(5, 0, 0, 0);

    foreleg1 = new AxisSegment(15);
    foreleg2 = new AxisSegment(15);
    arm1 = new AxisSegment(12);
    arm2 = new AxisSegment(12);
    forearm1 = new AxisSegment(12);
    forearm2 = new AxisSegment(12);

    ...

    leg1.AddChildElement(foreleg1, PivotPoint.P2, Layer.BackGround);
    leg2.AddChildElement(foreleg2, PivotPoint.P2, Layer.ForeGround);
    arm1.AddChildElement(forearm1, PivotPoint.P2, Layer.BackGround);
    arm2.AddChildElement(forearm2, PivotPoint.P2, Layer.ForeGround);

    trunk.AddChildElement(leg1, PivotPoint.P2, Layer.BackGround);
    trunk.AddChildElement(leg2, PivotPoint.P2, Layer.ForeGround);

    trunk.AddChildElement(arm1, PivotPoint.P1, Layer.BackGround);
    trunk.AddChildElement(arm2, PivotPoint.P1, Layer.ForeGround);

    head.AddChildElement(trunk, PivotPoint.P2, Layer.ForeGround);

    ...

    this.Children.Add(head);
}

Setting Up Chained Animations

Here is the heart of our stick figure animation. The SetAngleAnimations method exists inside the BaseSegment class, and defines a sequence of animations from a given array of predefined angles. All you have to do is pass to the method the name of the animation key, an array of angles (which will become the start angle and end angle for each stick member), and finally define whether the animation is continuous or not. Notice that for a given array of N angles, the method not only creates N - 1 animations, but also implements the Completed event of each animation, so that after any animation is completed, another animation is started:

public void SetAngleAnimations(string key, int[] angles, bool repeatForever)
{
    List<DoubleAnimation> angleAnimationList;
    if (!angleAnimationDictionary.ContainsKey(key))
    {
        angleAnimationList = new List<DoubleAnimation>();
        angleAnimationDictionary.Add(key, angleAnimationList);
    }
    else
    {
        angleAnimationList = angleAnimationDictionary[key];
    }

    angleAnimationList.Clear();
    for (int i = 0; i < angles.Length - 1; i++)
    {
        DoubleAnimation da = new DoubleAnimation()
            {
                Name = "da" + i.ToString(),
                Duration = 
                  new Duration(new TimeSpan(0, 0, 0, 0, minAnimationDuration))
            };

        angleAnimationList.Add(da);
    }

    for (int i = 0; i < angleAnimationList.Count; i++)
    {
        angleAnimationList[i].From = angles[i];
        angleAnimationList[i].To = angles[i + 1];
        if (i < angleAnimationList.Count - 1)
        {
            angleAnimationList[i].Completed += (sender, e) =>
                {
                    var clock = sender as AnimationClock;
                    var animation = clock.Timeline as DoubleAnimation;
                    int nextIndex = Convert.ToInt32(
                       (animation.Name.Replace("da", ""))) + 1;
                    this.BeginAngleAnimation(angleAnimationList[nextIndex]);
                };
        }
        else
        {
            if (repeatForever)
            {
                angleAnimationList[i].Completed += (sender, e) =>
                {
                    var clock = sender as AnimationClock;
                    var animation = clock.Timeline as DoubleAnimation;
                    int nextIndex = 0;
                    this.BeginAngleAnimation(angleAnimationList[nextIndex]);
                };
            }
        }
    }
}

That being said, let's take a look at the SetupAngleAnimations method, which defines the animations for each member of Mr. StickMan's body:

private void SetupAngleAnimations()
{
    leg1.SetAngleAnimations("walkToEast", 
       new int[] { MAX_LEG_ANGLE_WALK, MAX_LEG_ANGLE_WALK, 0, 
       -MAX_LEG_ANGLE_WALK, 0 }, false);
    leg2.SetAngleAnimations("walkToEast", 
       new int[] { -MAX_LEG_ANGLE_WALK, -MAX_LEG_ANGLE_WALK, 0, 
       MAX_LEG_ANGLE_WALK, 0 }, false);
    foreleg1.SetAngleAnimations("walkToEast", 
       new int[] { MIN_FORELEG_ANGLE_WALK, MAX_FORELEG_ANGLE_WALK, 0, 
       MIN_FORELEG_ANGLE_WALK, 0 }, false);
    foreleg2.SetAngleAnimations("walkToEast", 
       new int[] { MAX_FORELEG_ANGLE_WALK, MIN_FORELEG_ANGLE_WALK, 0, 
       MAX_FORELEG_ANGLE_WALK, 0 }, false);
    arm1.SetAngleAnimations("walkToEast", 
       new int[] { 0, -MAX_ARM_ANGLE_WALK, 0, MAX_ARM_ANGLE_WALK, 0 }, false);
    arm2.SetAngleAnimations("walkToEast", 
       new int[] { 0, MAX_ARM_ANGLE_WALK, 0, -MAX_ARM_ANGLE_WALK, 0 }, false);
    forearm1.SetAngleAnimations("walkToEast", 
       new int[] { 0, MIN_FOREARM_ANGLE_WALK, 0, MAX_FOREARM_ANGLE_WALK, 0 }, false);
    forearm2.SetAngleAnimations("walkToEast", 
       new int[] { 0, -MIN_FOREARM_ANGLE_WALK, 0, -MAX_FOREARM_ANGLE_WALK, 0 }, false);

    leg1.SetAngleAnimations("walkToWest", 
       new int[] { -MAX_LEG_ANGLE_WALK, -MAX_LEG_ANGLE_WALK, 0, 
       MAX_LEG_ANGLE_WALK, 0 }, false);
    leg2.SetAngleAnimations("walkToWest", 
       new int[] { MAX_LEG_ANGLE_WALK, MAX_LEG_ANGLE_WALK, 0, 
       -MAX_LEG_ANGLE_WALK, 0 }, false);
    foreleg1.SetAngleAnimations("walkToWest", 
       new int[] { -MIN_FORELEG_ANGLE_WALK, -MAX_FORELEG_ANGLE_WALK, 0, 
       -MIN_FORELEG_ANGLE_WALK, 0 }, false);
    foreleg2.SetAngleAnimations("walkToWest", 
      new int[] { -MAX_FORELEG_ANGLE_WALK, -MIN_FORELEG_ANGLE_WALK, 0, 
      -MAX_FORELEG_ANGLE_WALK, 0 }, false);
    arm1.SetAngleAnimations("walkToWest", 
       new int[] { 0, MAX_ARM_ANGLE_WALK, 0, -MAX_ARM_ANGLE_WALK, 0 }, false);
    arm2.SetAngleAnimations("walkToWest", 
       new int[] { 0, -MAX_ARM_ANGLE_WALK, 0, MAX_ARM_ANGLE_WALK, 0 }, false);
    forearm1.SetAngleAnimations("walkToEast", 
       new int[] { 0, -MIN_FOREARM_ANGLE_WALK, 0, -MAX_FOREARM_ANGLE_WALK, 0 }, false);
    forearm2.SetAngleAnimations("walkToEast", 
       new int[] { 0, MIN_FOREARM_ANGLE_WALK, 0, MAX_FOREARM_ANGLE_WALK, 0 }, false);

    leg2.SetAngleAnimations("kickToEast", new int[] { -15, -45, -90, -15, 0 }, false);
    foreleg2.SetAngleAnimations("kickToEast", new int[] { 0, 90, 15, 15, 0 }, false);
    arm1.SetAngleAnimations("kickToEast", new int[] { 0, 0, 0, 0, 0 }, false);
    arm2.SetAngleAnimations("kickToEast", new int[] { 0, MAX_ARM_ANGLE_WALK / 2, 
    MAX_ARM_ANGLE_WALK, MAX_ARM_ANGLE_WALK / 2, 0 }, false);
    forearm1.SetAngleAnimations("kickToEast", 
      new int[] { 0, -MAX_FOREARM_ANGLE_WALK * 2, -MAX_FOREARM_ANGLE_WALK * 2, 
      -MAX_FOREARM_ANGLE_WALK * 2, 0 }, false);
    forearm2.SetAngleAnimations("kickToEast", 
       new int[] { 0, MIN_FOREARM_ANGLE_WALK * 2, MIN_FOREARM_ANGLE_WALK * 2, 
       MIN_FOREARM_ANGLE_WALK * 2, 0 }, false);

    leg2.SetAngleAnimations("kickToWest", new int[] { 0, 0, 90, 15, 0 }, false);
    foreleg2.SetAngleAnimations("kickToWest", new int[] { 0, -90, -15, -15, 0 }, false);
    arm1.SetAngleAnimations("kickToWest", new int[] { 0, 0, 0, 0, 0 }, false);
    arm2.SetAngleAnimations("kickToWest", 
       new int[] { 0, -MAX_ARM_ANGLE_WALK / 2, -MAX_ARM_ANGLE_WALK, 
       -MAX_ARM_ANGLE_WALK / 2, 0 }, false);
    forearm1.SetAngleAnimations("kickToWest", 
       new int[] { 0, MAX_FOREARM_ANGLE_WALK * 2, MAX_FOREARM_ANGLE_WALK * 2, 
       MAX_FOREARM_ANGLE_WALK * 2, 0 }, false);
    forearm2.SetAngleAnimations("kickToWest", 
       new int[] { 0, -MIN_FOREARM_ANGLE_WALK * 2, -MIN_FOREARM_ANGLE_WALK * 2, 
       -MIN_FOREARM_ANGLE_WALK * 2, 0 }, false);
}

Notice what's being done here: The SetAngleAnimations method is doing all the boring task of defining the rotation animations for us and wiring up those animations with the corresponding stick figure members. Besides, you could create more animations just by adding more elements to the int[] array passed to the SetAngleAnimations method.

What's great about this technique is that you don't have to rotate or move each segment independently anymore - when you move or rotate a "parent" member (in the member hierarchy), all child members will move or rotate automatically! Then we no more have a bunch of pieces dropped on the screen, but a much more consistent "body". Although this is a stick figure animation, it could be easily modified to create structured body animations such as windmills, Ferris wheels, robotic arms, mechanical engines, and so on - sky is the limit!

So after we set up the classes, Mr. StickMan can easily walk around and kick with pretty little effort. I'm sure you could add more interesting movements, such as running, or even doing a "Roundhouse Kick" just like Chuck Norris.

Final Considerations

I'd like to thank you for the patience for reading the article, and I want to know what you think about the concepts presented here. I'm sure there are some improvements that can be made, so please give your feedback, especially if this article was useful for you in some way.

History

  • 2010-09-18: Initial version.

License

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

Share

About the Author

Marcelo Ricardo de Oliveira
Software Developer
Brazil Brazil
Marcelo Ricardo de Oliveira is a senior software developer who lives with his lovely wife Luciana and his little buddy and stepson Kauê in Guarulhos, Brazil, is co-founder of the Brazilian TV Guide TV Map and currently works for ILang Educação.
 
He is often working with serious, enterprise projects, although in spare time he's trying to write fun Code Project articles involving WPF, Silverlight, XNA, HTML5 canvas, Windows Phone app development, game development and music.
 
Published Windows Phone apps:
 
 
Awards:
 
CodeProject MVP 2012
CodeProject MVP 2011
 
Best Web Dev article of March 2013
Best Web Dev article of August 2012
Best Web Dev article of May 2012
Best Mobile article of January 2012
Best Mobile article of December 2011
Best Mobile article of October 2011
Best Web Dev article of September 2011
Best Web Dev article of August 2011
HTML5 / CSS3 Competition - Second Prize
Best ASP.NET article of June 2011
Best ASP.NET article of May 2011
Best ASP.NET article of April 2011
Best C# article of November 2010
Best overall article of November 2010
Best C# article of October 2010
Best C# article of September 2010
Best overall article of September 2010
Best overall article of February 2010
Best C# article of November 2009

Comments and Discussions

 
GeneralMy vote of 5 PinmvpMika Wendelius25-Sep-12 18:58 
QuestionVery nice PinmemberCIDev19-Sep-12 20:00 
AnswerRe: Very nice PinmvpMarcelo Ricardo de Oliveira22-Sep-12 12:50 
GeneralMy Vote of 5 PinmemberRaviRanjankr18-Jul-11 4:49 
GeneralRe: My Vote of 5 PinmvpMarcelo Ricardo de Oliveira18-Jul-11 6:19 
GeneralMy vote of 5 Pinmemberpophelix2-Apr-11 20:55 
GeneralRe: My vote of 5 PinmvpMarcelo Ricardo de Oliveira7-Apr-11 4:44 
GeneralMy vote of 5 PinmemberMSHAO9-Dec-10 13:30 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira11-Dec-10 6:49 
GeneralMy vote of 5 also PinmemberRichard Weselny25-Nov-10 2:31 
GeneralRe: My vote of 5 also PinmemberMarcelo Ricardo de Oliveira25-Nov-10 9:48 
GeneralMy vote of 5 PinmemberRichard Weselny25-Nov-10 2:31 
GeneralMy vote of 5 PinmemberBaesky27-Oct-10 21:10 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira28-Oct-10 2:02 
GeneralMy vote of 5 PinmemberAndre' Gardiner27-Oct-10 12:11 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira27-Oct-10 21:08 
GeneralMy vote of 5 PinmvpAbhijit Jana26-Oct-10 7:49 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira26-Oct-10 13:09 
GeneralCongrats! PinmvpAl-Farooque Shubho26-Oct-10 0:52 
GeneralRe: Congrats! PinmemberMarcelo Ricardo de Oliveira26-Oct-10 3:52 
GeneralMuito bom (very good) Pinmemberantoniohlopes25-Oct-10 15:13 
GeneralRe: Muito bom (very good) PinmemberMarcelo Ricardo de Oliveira26-Oct-10 0:23 
GeneralThe whole Brazilian coders community is proud of you!! PinmemberGerson Freire25-Oct-10 11:13 
GeneralRe: The whole Brazilian coders community is proud of you!! PinmemberMarcelo Ricardo de Oliveira25-Oct-10 12:46 
GeneralMy vote of 5 PinmvpJosh Fischer20-Oct-10 6:09 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira21-Oct-10 0:25 
GeneralMy vote of 5 PinmemberJFergulbops14-Oct-10 23:19 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira15-Oct-10 4:20 
GeneralMy vote of 5 PinmemberJWhattam14-Oct-10 13:36 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira15-Oct-10 4:18 
GeneralVote of 5 PinmemberKelvin Armstrong14-Oct-10 1:07 
GeneralRe: Vote of 5 PinmemberMarcelo Ricardo de Oliveira14-Oct-10 6:13 
GeneralMy vote of 5 PinmemberSteveQ5611-Oct-10 22:00 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira13-Oct-10 1:41 
GeneralMy vote of 5 PinmemberAbhinav S7-Oct-10 7:45 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira8-Oct-10 6:24 
GeneralInteresting PinmemberCIDev25-Sep-10 0:57 
GeneralRe: Interesting PinmemberMarcelo Ricardo de Oliveira25-Sep-10 4:51 
GeneralMy vote of 5 Pinmembersashidhar23-Sep-10 9:16 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira24-Sep-10 1:37 
GeneralMy vote of 5 PinmemberMass Nerder23-Sep-10 1:44 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira23-Sep-10 7:26 
GeneralMy vote of 5 PinmentorBrij22-Sep-10 5:34 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira22-Sep-10 6:04 
GeneralMy vote of 5 PinmemberJeroen Vonk22-Sep-10 2:36 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira22-Sep-10 2:40 
GeneralMy vote of 5 Pinmemberlinuxjr21-Sep-10 10:44 
GeneralRe: My vote of 5 PinmemberMarcelo Ricardo de Oliveira21-Sep-10 10:55 
GeneralNice Demo! Another 5. Pinmemberthompsons21-Sep-10 7:47 
GeneralRe: Nice Demo! Another 5. PinmemberMarcelo Ricardo de Oliveira21-Sep-10 8:44 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 14 Oct 2010
Article Copyright 2010 by Marcelo Ricardo de Oliveira
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid