WindowlessControls Tutorial - Part 4: Data Binding

databind

A colleague of mind was asking me a few questions about WindowlessControls, which reminded me that I had been neglecting this tutorial series!

Anyhow... Data binding is all the rage in UI development these days. In short, data binding is a way to have your UI elements be "bound" to your internal data structures. Changes to the data will be reflected as changes in the UI. WPF does this quite nicely with the ItemsControl class. So, that provided a template for the implementation of WindowlessControl's version of ItemsControl. This tutorial will demonstrate how to create an image gallery/viewer application using a data binding technique.

We'll start out with the form template similar to the the previous tutorial. A form with a background image and a foreground which contains the ItemsControl object:

// set up the background bitmap and control
PlatformBitmap backgroundBitmap = PlatformBitmap.FromResource("Wallpaper.jpg");
WindowlessImage background = new WindowlessImage(backgroundBitmap);
background.Stretch = Stretch.Uniform;
overlay.Controls.Add(background);

// set up the foreground
StackPanel foreground = new StackPanel();
overlay.Controls.Add(foreground);

// set up the ItemsControl which will hold the images
myItemsControl.BackColor = Color.Transparent;
// the images will be contained in a wrap panel
myItemsControl.Control = new WrapPanel();
// this tells the ItemsControl what is used to represent the content items
myItemsControl.ContentPresenter = typeof(ImageResourcePresenter);
foreground.Controls.Add(myItemsControl);
An ItemsControl contains 3 properties of interest:
  • ContentPresenter - This is the type of WindowlessControl that will represent your data. It must implement IInteractiveContentPresenter.
  • Control - This is the panel that will lay out your ContentPresenters.
  • Items - This is the collection of objects that will be bind to the UI.
// set up the ItemsControl which will hold the images
myItemsControl.BackColor = Color.Transparent;
// the images will be contained in a wrap panel
myItemsControl.Control = new WrapPanel();
// this tells the ItemsControl what is used to represent the content items
myItemsControl.ContentPresenter = typeof(ImageResourcePresenter);
foreground.Controls.Add(myItemsControl);

Let's start out by implementing the content presenter. Let's set the following goals for our presenter:

  • Display the image (obviously).
  • Show a highlight border around the image when it is focused.
  • The image should have a grow/shrink animation when clicked.

Here's the implementation of the content presenter:

// an ImageResourcePresenter will be shown as a WindowlessImage
// with a WindowlessBackground that is visible when it is selected
class ImageResourcePresenter : OverlayPanel, IInteractiveContentPresenter
{
WindowlessRectangle myRectangle = new WindowlessRectangle();
WindowlessImage myImage = new WindowlessImage();

public ImageResourcePresenter()
{
// spacing between images
Margin = new Thickness(5, 5, 5, 5);
// limit the maximum size of an item
MaxWidth = 100;
MaxHeight = 100;
// stretch to fit
HorizontalAlignment = WindowlessControls.HorizontalAlignment.Stretch;
VerticalAlignment = VerticalAlignment.Stretch;

// allow a 5 pixel border between the image and the rectangular selected background
myImage.Margin = new Thickness(5, 5, 5, 5);
myImage.VerticalAlignment = VerticalAlignment.Center;
myImage.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Center;

// set up the rectangle color and make it fill the region
myRectangle.Color = SystemColors.Highlight;
myRectangle.HorizontalAlignment = WindowlessControls.HorizontalAlignment.Stretch;
myRectangle.VerticalAlignment = VerticalAlignment.Stretch;
// the rectangle does not paint by default
myRectangle.PaintSelf = false;

Controls.Add(myRectangle);
Controls.Add(myImage);
}

#region IInteractiveStyleControl Members

public void ApplyFocusedStyle()
{
// make the rectangle paint to denote that it is focused
myRectangle.PaintSelf = true;
}

public void ApplyClickedStyle()
{
// when clicked, remove the margin, so the image can "grow"
myImage.Margin = Thickness.Empty;
}

#endregion

#region IContentPresenter Members

string myName;
public object Content
{
get
{
return myName;
}
set
{
myName = value as string;
// see if this image is a file or a resource, and load it
if (!File.Exists(myName))
{
myImage.Bitmap = PlatformBitmap.FromResource(myName);
}
else
{
myImage.Bitmap = PlatformBitmap.From(myName);
}
}
}

#endregion
}

 

So to create this presenter, start with an OverlayPanel, which houses a background (the focused state rectangle) and a foreground (the WindowlessImage). The interesting bit of the code is the implementation of the Content property. Let's come back to that later.

So, next is to populate the Items on the ItemsControl with images. The follow code will search for all image resources in the assembly and also any image files that maybe in \My Documents\My Pictures.

// let's get a list of image resources
Assembly ass = Assembly.GetCallingAssembly();
string[] names = ass.GetManifestResourceNames();
foreach (string name in names)
{
foreach (string extension in imageExtensions)
{
if (name.EndsWith(extension, StringComparison.CurrentCultureIgnoreCase))
{
myItemsControl.Items.Add(name);
break;
}
}
}

// now let's search the file system for images
foreach (string name in Directory.GetFiles("\\My Documents\\My Pictures"))
{
foreach (string extension in imageExtensions)
{
if (name.EndsWith(extension, StringComparison.CurrentCultureIgnoreCase))
{
myItemsControl.Items.Add(name);
break;
}
}
}

Now, rewinding to the Content property. Behind the scenes, when an object is added to the Items collection, the ItemsControl creates an instance of the given ContentPresenter and sets the Content property to the item to which it is bound. When the Content value changes, the IInteractiveContentPresenter should update the UI representation accordingly. As you can see above, the ContentPresenter determines if the Content is a image file or an image resource, and then loads the image from the appropriate source.

That's all there is to data binding! Changing your to add or remove images is as simple as updating the Items collection. By using data binding and a proper custom WindowlessControls, rich and flexible user interfaces can be quickly developed for Windows Mobile.

Source code to the updated WindowlessControls tutorial.

0 comments: