Create a Shaped 3D Control with GDI+

Preventing Properties from Appearing in the Properties Window

Other properties were removed from the designer either arbitrarily or because they cause design-time errors. For example, no property editor exists for Pen objects as yet (see my book Visual Basic .NET Power Coding [Addison-Wesley, 2003] for more on custom property editors); thus, the designer would not be able to adequately permit modifying a Pen at design time. (You probably could write a custom property editor in terms of a Pen color, but that's another article.)

Public properties are visible in the Properties window by default. As Listing 5 shows, to make a property invisible, you tag the property with the BrowsableAttribute, passing False to the attribute. Remember that the Attribute suffix is dropped from attributes by convention.

Listing 5: Use the BrowsableAttribute initialized with False to remove properties from the design-time environment.

<Browsable(False)> _
Public Property CubeSize() As CubeSize
Get
Return FCube.Size
End Get
Set(ByVal Value As CubeSize)
FCube.Size = Value
Invalidate()
End Set
End Property
<Browsable(False)> _
Public ReadOnly Property CubeX() As Integer
Get
Return FCube.X
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property CubeY() As Integer
Get
Return FCube.Y
End Get
End Property
<Browsable(False)> _
Public Property CubePen() As Pen
Get
Return FPen
End Get
Set(ByVal Value As Pen)
FPen = Value
End Set
End Property
<Browsable(False)> _
Public ReadOnly Property Cube() As Cube
Get
Return FCube
End Get
End Property

The non-browsable properties in Listing 5 complete the implementation of the 3D Cube control.

Shaping the Control

.NET supports shaped controls directly. In earlier versions of VB, one had to have a pretty comprehensive understanding of device contexts and the Windows API to create shaped controls. While you'll find some pretty good articles on shaped VB6 Forms with the API, the conspicuous absence of information about non-rectilinear forms suggests that this topic is fairly obscure.

Controls in .NET have a Region property, which is an instance of the Region class. This class supports Transforms, which in turn are an instance of the Matrix class. The Region class permits shaping and the Transform property of the Region class makes it easier to twist, turn, and rotate regions. In this example, all you had to do was get the bounding region of the cube, assign that to the containing control, and violà! You have a shaped control. Because Forms are controls, you can use the same technique to create shaped Windows forms.

Defining a Toolbar Bitmap

VS.NET contains several designers and editors. One such designer is icon and bitmap designer. By adding a bitmap item (select Project|Add New Item|Bitmap File) to your project, you can add a bitmap and draw the bitmap for your control's Toolbar representation or add an existing bitmap to the project.

If you add a new bitmap file to your project, VS.NET opens the designer and makes a new Image menu available. The Image menu contains menu items and links to toolbars that permit drawing a bitmap from scratch. Figure 2 shows a bitmap that represents an approximation of the control's visual representation. The preview window (see Figure 2, middle) shows you how the bitmap will appear with its actual size, and the drawing window (see Figure 2, right) is a zoomed-in view that makes it easier to draw the bitmap.

To associate this bitmap with your custom control, you need to use the ToolboxBitmapAttribute and the path to the bitmap file or a resource type. (This demonstration uses the latter approach.) The bitmap can be a 16x16- or 32x32-pixel image. Listing 6 shows the ToolboxBitmapAttribute applied to your control class header.

Listing 6: Use the ToolboxBitmapAttribute to add a graphic to the toolbox along with your control.

Select the Cube3d.bmp file in the Solution explorer, press F4 to display the Properties window, and change the Build Action to Embedded Resource (see Figure 3).

Finally, specify the resource type (GetType(Cube3d) in the ToolboxBitmapAttribute for your control class.

Figure 3: Embedding a bitmap is an easy way to drag it along with your application.

(The IDE seems to be a bit particular about the image details, so much so that I did not gratuitously mention my book. Rather, I mentioned the book because I had to go back and check when the image did not show up in the toolbox the first time.)

The final steps include copying the cube3d.bmp to the folder containing the assembly (or including the full path in the ToolboxBitmapAttribute) or embedding the bitmap as a resource, compiling the library containing your custom control, and adding the library to the toolbox.