WinForms Animation (part 2)

A small update to this previous post on doing very simply animations in WinForms. Having a base class to represent individual graphic elements, then using the built in Transforms (rotate, scale, translate) to individually paint each element works pretty well. However, there are a couple of issues with this approach.

The first issue becomes apparent when some level of interaction is required with the graphic elements. For example, the ability to select one using the mouse. In the previous example the individual elements never know their transformed location themselves, therefore they can’t perform their own hit-testing. Its a shame there isn’t some way to have the transforms applied in reverse – to convert a form co-ordinate into a local point. The simple solution to this that I opted for with PhotoPlay was to simply perform my own translations.

First step was to add a property called TransformedBounds to the base class that translates the element’s local bounds to world co-ordinates using some good old fashioned trig. (Angle), multiplication (Scale) and addition (Centre). Also an overridable implementation of a HitTest. The base implementation caters for polygons (e.g. rectangles, triangles, stars) but an override is required for more complex shapes – particularly those with curves.

    public class InteractiveDrawingElement : DrawingElement
    {
        private bool isHot;

        /// <summary>
        /// Gets or sets whether the element is “hot” – normally this is when the cursor is located over the element.
        /// </summary>
        public bool IsHot
        {
            get { return isHot; }
            set { isHot = value; }
        }

        /// <summary>
        /// Determines whether the supplied<paramref name=”hitPoint”/> is contained within the
        /// element.
        /// </summary>
        /// <param name=”hitPoint”>The point to be tested.</param>
        /// <returns><see langword=”true”/> if<paramref name=”hitPoint”/> is considered to be a “hit”
        /// on the drawing element,<see langword=”false”/> otherwise.</returns>
        public virtual bool HitTest(Point hitPoint)
        {
            return DrawingSupport.PolygonContains(TransformedVertices, hitPoint);
        }
    }

The second issue is allowing for parts of the element rendering to ignore aspects of the transformation. The obvious example of this is not wanting to scale things like anchors/handles. This can be handled via an OnRawPaint method that I call before transformation occurs but it means that any portion of the transform that you do want (e.g. rotation) must now be manually coded. The second example I had was rendering a shadow on a photo. Initially I just painted a dark semi-transparent rectangle behind the photo frame. But rotating the frame also caused the shadow to rotate, meaning that if an image is rotate 180 degrees its shadow is now offset to the top right instead of the bottom left. That doesn’t make a lot of sense since shadows should also be offset for all objects in a consistent direction regardless of their rotation. This required a dirty hack to fix and I didn’t bother catering for it in the base class.

The updated source code for the WinForms Transitions is here. A ClickOnce online only example is here.

Ok – so enough WinForms and rants (the monitor arrived on the weekend ) – back to WPF.

2 thoughts on “WinForms Animation (part 2)”

  1. Thanks so much for sharing this code! Can you also recommend a good Winform book? I would like something that focuses on the best architecture for a winform app, not too basic.

  2. Sorry Julia – I’ve never read a WinForms book so I can’t really recommend any. If you want to get into some cool user interface stuff then I strongly recommend you check out WPF using Visual Studio 2008. For WPF I can strongly recommend Adam Nathan’s WPF Unleashed. All of the hit testing stuff is much easier in WPF (its built in) and you can get some really smooth animation effects happening with minimal effort. That being said its certainly a lot of new stuff to learn if you’re already familiar with WinForms!

    However, if you really want to get into some serious architecture then I’d recommend reading some of the Microsoft Patterns and Practices stuff, or checking out their Enterprise Library or even better their Client Application Block and incubated Acropolis project.

Comments are closed.