Aspect Ratio Picture Box control

Screenshot of sample application showing the use of an AspectRatioPictureBox controlOne feature missing from the PictureBox control within the .NET Compact Framework is the Zoom SizeMode. This mode makes the image contained within the PictureBox as large as possible while still maintaining its original aspect ratio. Luckily this feature is easy to implement as a custom control.

Scaling an Image

The ratio of a picture’s width to height is known as its aspect ratio. An image with an aspect ratio greater than 1 means that it is wider than it is high (landscape image). While an image with an aspect ratio of less than one is taller than it is wide (portrait image). If the aspect ratio is exactly 1 the image is square.

By comparing the aspect ratio of an image against the aspect ratio of our control we can determine if the best axis to stretch the image (in order to maximise its size) is vertically or horizontally. Once we have determined the maximum width or height of our scaled image we can then utilise the aspect ratio to calculate the other dimension in order to keep the same aspect ratio.

Creating a custom control

There are two main types of custom controls within a System.Windows.Forms based application, those that derive from the Control base class and those that derive from the UserControl base class. For this kind of custom control, deriving from System.Windows.Forms.Control is the best approach since we are after a fairly light weight control.

To make a custom control we simply need to declare a class which derives from Control:

using System.Windows.Forms;
 
public class AspectRatioPictureBox : Control
{
}

The code sample above is a complete custom control. Once it is compiled you will be able to place an AspectRatioPictureBox control onto a form, in the same way you would any other control such as a Button or Label.

The control however is quite boring, being a completely white rectangle making it indistinguishable from the form it is placed upon. Before we cover how to paint more attractive contents, we need a way for the user to specify the image they would like to display. The easiest way to do this is to implement a public property by adding the following to our class definition:

private Bitmap photo;
 
public Bitmap Image
{
   get { return photo; }
   set
   {
     photo = value;
 
     // Redraw the contents of the control
     Invalidate();
   }
}

Any public property exposed by our control will be accessible via the Properties window within the Forms Designer when the user utilises our control.

Notice the call to the Control.Invalidate method within the Image property setter? This is important, as this is the call which notifies the operating system that our control has changed state and needs to be redrawn. If the control is not invalidated, the OS will not attempt to redraw it and the user would not be able to see the new image that has just been provided. In general any property which affects the onscreen presentation of a custom control should invalidate it.

Now that we have a way to specify the bitmap we want to display, we can finally implement the code that will paint the contents of the control. We do this by overriding the OnPaint method as follows:

protected override void OnPaint(PaintEventArgs e)
{
  if (photo != null)
  {
    float controlAspect = (float)ClientSize.Width / (float)ClientSize.Height;
    float photoAspect = (float)photo.Width / (float)photo.Height;
 
    if (photoAspect < controlAspect)
    {
      // Stretch the height of the photo to match
      // the height of the control
      ....
    }
    else
    {
      // Stretch the width of the photo to match
      // the width of the control
      ....
    }
  }
}

The framework will call the OnPaint method each time the OS needs the control’s contents to be repainted onto the screen. For a complete implementation of this method see the sample application downloadable below.

Using a custom control

Screenshot showing AspectRatioPictureBox control within the Toolbox of Visual StudioUsing custom controls within your projects is reasonably straight forward. Once you have created your new custom control class you simply need to recompile your project in order for the control to be picked up by Visual Studio and displayed in the Toolbox as a custom control. This is shown in the above screenshot. Once an instance of the custom control has been placed onto a form its properties can be configured via the standard Property window.

Unlike the Desktop development environment, Smart Device custom controls do not directly utilise attributes such as [Description()] to configure their appeance and behaviour within the Visual Studio IDE. Instead Smart Device custom controls utilise what is called an XMTA file. Customising the design time experience of your custom controls will be discussed in a future blog post.

Sample Application

[Download aspectratiopictureboxtest.zip - 25.7KB]

A small sample application is available for download. It demonstrates the use of the AspectRatioPictureBox custom control developed within this blog entry in a number of different scenarios.

Feel free to utilise the included AspectRatioPictureBox.cs file within your own projects. As an added feature an additional property called “Restricted” has been added. When the Restricted property of the control is set to true the image will not be stretched any larger than it’s original size. When “unrestricted” the image will be stretched to take the full width or height of the control, even if that means stretching the image beyond it’s original size. The restricted mode is useful for image viewing applications where you don’t want to stretch small images and degrade their quality, while still ensuring large images are scaled down to fit the screen.

Leave a Reply