WindowlessControls Tutorial Part 1

I've mentioned in passing several times that I use a home brew UI framework to do all my Windows Mobile development. The UI framework implements many things that are missing from System.Windows.Forms:

  • Relative Layout of Screen Elements - Controls are positioned relative to each other and to the screen, not at absolute positions, which is the behavior of Windows Forms. The benefit of relative layout is that your form can fit any screen form factor.
  • Transparent Controls - There are ways to get transparencies into Windows Mobile, but none elegant.
  • Smart Key Navigation - Up, down, left, and right actually navigate you in that direction. Very handy for non-touch screens.
  • Data Driven Controls - Controls are driven by the data they represent. This allows for a clean MVC pattern which is not available with Windows Forms.
  • Simple Animation System - Creating and handling "focus" and "click" states for buttons is very simple.
  • Custom Controls - This framework can be used to create rich custom controls quite easily.
  • Hierarchical Events - All events bubble upwards in the control hierarchy and can be handled at any level. Similar to WPF.
  • XAML style layout - Create your user interface using XML.

This framework can and has been used to create aesthetically pleasing applications, such as Klaxon; something that is generally very difficult to do in Windows Mobile. However, for tutorial purposes, I'm going to start with a very simple "Hello World" style application. This tutorial will demonstrate the following (click here for the source code):

  • Add a WindowlessControl "Host" to your Windows Form application.
  • Add controls to the "Host" to be handled by the layout and rendering engine.
  • Manipulate the layout of these controls.
  • Handle click events at different points in the control hierarchy.
  • Draw some text and a simple image.

WindowlessControls is a complete layout and rendering system. You can drop a WindowlessControl "Host" onto a Windows Form, and then begin adding other WindowlessControls into it to take advantage of its features.

  1. Create a Windows Mobile Windows Forms application.
  2. Add a Reference to WindowlessControls.
  3. Compile.
  4. Drag a VerticalStackPanelHost (named myHost below) onto the Form. Dock the VerticalStackPanelHost so it fills the entire form. This will become your gateway into the land of WindowlessControls. A StackPanel is similar to the WPF StackPanel. It lays out all elements inside it in a linear fashion. A VerticalStackPanelHost would thus lay out all elements vertically.

image

Now you are ready to add controls. First, let's add a simple label that says "Hello World!". We'll add this code into the Form's constructor:

public HelloWorld()
{
    InitializeComponent();

    // myHost is a Control that provides a transition from System.Windows.Forms to WindowlessControls.
    // myHost.Control is the WindowlessControls.WindowlessControl that is "hosted" in the Windows.Windows.Forms.Control.
    StackPanel stack = myHost.Control;
    // make the stack panel to stretch to fit the width of the screen
    stack.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Stretch;

    // hello world!
    WindowlessLabel hello1 = new WindowlessLabel("Hello World!");
    stack.Controls.Add(hello1);

That was painless enough. This will produce the left aligned "Hello World!" seen here:

image

Now let's try adding some larger text that is centered horizontally and some text that is right aligned:

// center this label and use a different font
Font center = new Font(FontFamily.GenericSerif, 20, FontStyle.Regular);
WindowlessLabel hello2 = new WindowlessLabel("Centered!", center);
hello2.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(hello2);

// right align this control
WindowlessLabel right = new WindowlessLabel("Right Aligned!");
right.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Right;
stack.Controls.Add(right);

image

Notice that there is no need to specify any positioning with the various screen elements. All their heights and widths are calculated by the layout system, and the labels are "stacked" on top of each other automatically. Another supported property of any WindowlessControl is a "Margin". This allows the developer to specify a small amount of padding between the Control and its content. For example, to draw some text with a 20 pixel margin all around it, set the Margin property:

// show that controls support margins
WindowlessLabel margin = new WindowlessLabel("Margin!");
margin.Margin = new Thickness(20, 20, 20, 20); // margins for the left, top, right, and bottom
stack.Controls.Add(margin);

image

As you can see, there is a visible 20 pixel margin along the top and left of the rendered text. Just like any other layout framework, WindowlessControls supports the concept of nested controls: you can place controls within other controls. An entire control group is then subject to the layout of its parent. For example, by creating a centered stack panel and adding two labels to it, all the children of the StackPanel end up being centered:

// nest controls within another control and center the parent
StackPanel child = new StackPanel();
child.Controls.Add(new WindowlessLabel("Nested"));
child.Controls.Add(new WindowlessLabel("Controls"));

image

Now, let's add a Hyperlink into that same StackPanel, and handle it's WindowlessClick event:

// create a clickable hyperlink
HyperlinkButton button = new HyperlinkButton("Click Me!");
child.Controls.Add(button);
button.WindowlessClick += (s, e) =>
    {
        MessageBox.Show("Hello!");
    };

 

image

As shown in the code, the click event is called WindowlessClick as opposed to Click. Click is the standard Windows Forms event, whereas WindowlessClick behaves differently. This is because all WindowlessControls bubble all Control events to every Host in its hierarchy. This means that the WindowlessClick event is also fired and available to be handled on "myHost", the top level control! Let's test this out:

// when the hyperlink is clicked, the event will bubble up to every host in the hierarchy
// watch for the event and handle it
myHost.WindowlessClick += (s, e) =>
    {
        if (s != myHost)
        {
            MessageBox.Show("A click event just bubbled up to me from " + s.GetType().ToString() + "!");
        }
    };
child.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(child);

image

Finally, let's draw a centered image on the screen. Grab an image and add it to your project. Set its Build Action to "Embedded Resource" in the properties pane. Then add the following code:

// draw a centered image
PlatformBitmap bitmap = PlatformBitmap.FromResource("mybrainhurts.jpg");
WindowlessImage image = new WindowlessImage(bitmap);
image.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;
stack.Controls.Add(image);

image

Done! Note that PlatformBitmap is different from System.Drawing.Bitmap. The problem with System.Drawing.Bitmap is that it does not support transparencies on Windows Mobile. However, the Imaging API available in Windows Mobile does support images with per pixel alpha. PlatformBitmap provides an abstraction layer around images: they either wrap standard Bitmap objects or they wrap an IBitmapImage from the Imaging API. The PlatformBitmap.Load function will handle that abstraction for you transparently, and choose the appropriate API based on the image type.

Anyhow, I understand this doesn't look that enticing yet, but worry not! Next article, I'll demonstrate the data driven controls and custom/composite controls. That's when things get interesting.

Click here to download the source code for this tutorial.

3 comments:

Unknown said...

Well you've captured my interest.
I looking forward to how this copes with a change in screen orientation.

Also how to place controls side by side.

Cheers,

Paul.

Anonymous said...

Thank you for these tutorials. Keep up the great job?

o grande eubage said...

Hello! Thx first for the great tutorial. I have experience programming in Java SE but never touched an .Net code before. Anyway last year I bought a WinMo device and this tutorial seems to be a great way to start coding for my device. Today I downloaded MS Visual Studio C# 2008 Express but couldn't find "Windows Mobile Windows Forms", what IDE I need?