Irregularly Shaped Forms
Irregularly shaped forms are often the trademark of cutting-edge consumer applications like photo editors, movie makers, and MP3 players. In the past, creating them required a fair bit of API wizardry. Now with .NET, creating a shaped form is almost effortless, thanks to the new GDI+ model that's included as part of the .NET framework.
To create a simple shaped window in .NET, all you need to do is create a form, and assign a new shape to its Region property (this is the same process followed to create a custom shaped control). There is more than one way to create a Region, but the easiest is by using the GraphicsPath class, which allows you to build up a complex shape out of as many subshapes as you need.
First, begin by importing the required GDI+ namespace:
using System.Drawing.Drawing2D;
You can then create and apply the GraphicsPath. The following example code defines an ellipse with the same bounds of the form. Once it's assigned to the Region property of the form, only the part of the form that fits inside the ellipse is displayed (see Figure 5-25).

Figure 5-25: A shaped form
private void ShapedForm_Load(object sender, System.EventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, this.Width, this.Height);
this.Region = new Region(path);
}
You can see part of the original window border at the top and bottom of the shaped form, and the single contained button in the middle. However, the form acts completely like an ellipse. For example, if you click in the cutout portion that the original rectangular form occupied (that is, just above the left edge of the ellipse), you will not select the form. Instead, you select whatever application is currently underneath the form. This convenience is a great step forward—with ordinary GDI code, shaped controls looked like shapes but still behaved like the original rectangles in many ways.
You can also create a shaped form made up of a combination of shapes. In fact, these shapes don't even need to overlap! The following example illustrates a more unusual shaped form, shown in Figure 5-26:
private void ShapedForm_Load(object sender, System.EventArgs e)
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, this.Width / 2, this.Height / 2);
path.AddRectangle(new Rectangle(this.Width / 2, this.Top / 2,
this.Width / 2, this.Top / 2));
path.AddEllipse(this.Width / 2, this.Height / 2, this.Width / 2,
this.Height \ 2);
this.Region = new Region(path);
}

Figure 5-26: A noncontiguous shaped form
Shaped Form Content
There are two problems you will quickly notice with shaped forms:
The Region defines a shape, but this shape does not provide any borders. Instead, a shaped form is just a geometric figure that reveals the underlying form.
Ordinary controls (like standard windows buttons) aren't well suited for a shaped form—the styles seem to clash.
To handle these problems, you need to create your graphical content from scratch. You can accomplish this by using GDI+ to create owner-drawn controls, as you'll see in 13. An easier approach is just to design the appropriate images in a dedicated graphics program and import them into your .NET controls.
For example, you can set the BackgroundImage property for the form to a picture that has the same shape you want to use, and includes a border. You can also substitute picture box controls for buttons. Figure 5-27 shows one such example.

Figure 5-27: An irregular form with graphical content
To make the images behave like buttons, some additional logic is required to offset the button when it is clicked. The event handlers shown in the following are reused for the MouseDown and MouseUp events of all four buttons.
private void pic_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
PictureBox pic = (PictureBox)sender;
pic.Top += 2;
pic.Left += 2;
}
private void pic_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
PictureBox pic = (PictureBox)sender;
pic.Top -= 2;
pic.Left -= 2;
}
Additionally, the images are enhanced to support hot tracking. Whenever the mouse pointer positions itself above a button, a different image is displayed. This image looks the same as the normal button image, but has its text highlighted in yellow. The code to implement this technique simply retrieves the required picture from a ListView control.
private void pic_MouseEnter(object sender, System.EventArgs e)
{
PictureBox pic = (PictureBox)sender;
int imageIndex = int.Parse((pic.Tag.ToString()));
pic.Image = imgSelectedButtons.Images[imageIndex];
}
private void pic_MouseLeave(object sender, System.EventArgs e)
{
PictureBox pic = (PictureBox)sender;
int imageIndex = int.Parse((pic.Tag.ToString()));
pic.Image = imgNormalButtons.Images[imageIndex];
}
You can try this code by running the IrregularlyShapedForms project included with the code download for this chapter.
Moving Shaped Forms
Another limitation of shaped forms is that they often omit the nonclient title bar portion, which allows the user to easily drag the form around the desktop. To remedy this problem, you need to add a control that takes over the responsibility for the form's title bar.
For example, you could add a picture box or a label control. This control needs to handle the MouseDown, MouseUp, and MouseMove events, and reposition the form accordingly (Figure 5-28). The code is similar to that used in

Figure 5-28: Moving a shaped form
private bool formDragging;
private Point pointClicked;
private void lblDrag_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
// Set drag mode on.
formDragging = true;
// Store the offset where the control was clicked.
pointClicked = new Point(e.X, e.Y);
}
private void lblDrag_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
if (formDragging)
{
Point pointMoveTo;
// Find the current mouse position in screen coordinates.
pointMoveTo = this.PointToScreen(new Point(e.X, e.Y));
// Compensate for the position the control was clicked.
pointMoveTo.Offset(-pointClicked.X, -pointClicked.Y);
// Compensate for the nonclient region (title bar).
// This code is not necessary if you explicitly hide the title bar
// by setting the form's BorderStyle to None.
pointMoveTo.Offset(0, -25);
// Move the form.
this.Location = pointMoveTo;
}
}
private void lblDrag_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
formDragging = false;
}
Forms with Holes
There's also one other approach to creating irregularly shaped forms. You can define a special color for the form that will automatically be cut out by setting the form's TransparencyKey property. For example, if you choose dark blue, all occurrences of dark blue in your form become invisible. This includes occurrences of the color in an image, a control, or even the form's background. In fact, these holes aren't just invisible—you can even click through them to activate a program underneath!
Figure 5-29 shows an example from the online samples that contains several picture box controls that contain the TransparencyKey color as their background. At runtime, these picture boxes disappear.

Figure 5-29: A form (with the desktop showing through)