Developing for Windows Mobile – Composing User Controls

Tonight I finished refactoring the mobile UI framework I’ve been putting together so that it can correctly handle composite elements. Previously I’d been able to handle a collection of polygons (Rectangles, Stars etc.). I’ve now introduced the concept of DrawingContainers that themselves have a collection of elements, any of which may be another DrawingContainer.

The idea is that I can now construct UI controls that themselves are composed of simple graphic primitives. Just like WPF right? Each graphic element can have its own animations and hit test capabilities and controls can be composed within each other to form richer user controls. All this is rendered to the hosting Windows.Forms.Control in a single double-buffered render.

The class diagram below gives an indication of where I’m currently at. Everything in the diagram has been implemented.

 

Spencen.Mobile.UI

As one example of compositing controls I used a multi-part windmill.

Windows Mobile Spinning Wheel Thing_Thumb

Defined in code as:

var center = new Point( hostCanvas.Width / 2, hostCanvas.Height / 2 );
var yellowBrush = new SolidBrush( Color.Yellow );
var panel = new Panel( hostCanvas ) { Size = hostCanvas.Size, Center = center };
var bar1 = new Panel( hostCanvas ) { Size = new Size( 200, 20 ), Center = new Point( center.X, center.Y - 190 ) };
var bar2 = new Panel( hostCanvas ) { Size = new Size( 200, 20 ), Center = new Point( center.X, center.Y + 190 ) };
panel.Children.Add( new Rectangle() { Size = new Size( 50, 400 ), Center = center } );
bar1.Children.Add( new Rectangle() { Size = bar1.Size, Position = new Point( 0, 0 ) } );
bar2.Children.Add( new Rectangle() { Size = bar1.Size, Position = new Point( 0, 0 ) } );
bar1.Children.Add( new Star() { Size = new Size( 75, 75 ), 
Center = new Point( bar1.Size.Width / 2 - 90, bar1.Size.Height / 2 ),
Background = yellowBrush } ); bar1.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar1.Size.Width / 2 + 90, bar1.Size.Height / 2 ),
Background = yellowBrush } ); bar2.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar2.Size.Width / 2 - 90, bar2.Size.Height / 2 ),
Background = yellowBrush } ); bar2.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar2.Size.Width / 2 + 90, bar2.Size.Height / 2 ),
Background = yellowBrush } ); panel.Children.Add( bar1 ); panel.Children.Add( bar2 ); panel.Transforms.Add( _rotateTransform ); _rotateTransform.RenderCenter = new Point( hostCanvas.Width / 2, hostCanvas.Height / 2 ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( _rotateTransform, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = 3600 } ); var barRotation = new RotateTransform(); bar1.Transforms.Add( barRotation ); bar2.Transforms.Add( barRotation ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( barRotation, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = -7200 } ); var starRotation = new RotateTransform(); bar1.Children[ 1 ].Transforms.Add( starRotation ); bar1.Children[ 2 ].Transforms.Add( starRotation ); bar2.Children[ 1 ].Transforms.Add( starRotation ); bar2.Children[ 2 ].Transforms.Add( starRotation ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( starRotation, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = 18000 } ); hostCanvas.View.Children.Add( panel );

Other features so that I’ve got so far:

  • Support for Behaviours. So far the only implementation is a DragBehavior that allows dragging any attached element along one or both axis. Even supports a “flick” by determining the angle and velocity on mouse up and applying an animation with a cubic easing function to simulate velocity decay.
  • Scrolling between views/pages using an easing function (and BitBlt).
  • Simple image support.

Other ideas:

  • Button and ItemsList controls.
  • Stack and custom (e.g. radial) layout panels.
  • Integration with platform APIs to allow drawing of rounded rectangles, gradient fills and to support alphas.
  • A transform for flipping vertically or horizontally.
  • Behaviour to support an ICommand style interface to allowing hooking UI interactions with a view model.