Toolbars

Toolbars usually provide access to features that are also accessible through menus, but there’s a tradeoff. Because a toolbar is always visible, it can be clicked without having to navigate through a menu structure, but toolbars have a slightly higher learning curve, because items are normally represented by buttons with a small bitmap; it is much harder to represent an operation unambiguously with a tiny picture than it is to describe it with some text in a menu.

In Windows Forms, toolbars are represented by the ToolBar class, and individual buttons on it are represented by the ToolBarButton class. Note that these classes provide a fairly basic style of toolbar—Windows Forms provides no support for undocking toolbars or even rearranging them.

The ToolBar Class

ToolBar is a fairly simple class. It inherits from Control and must be docked; most applications dock the toolbar to the top of the window. ToolBar is a simple class to use—it adds only a few properties to its base class.

The class provides an Appearance property, which must be one of the members of the ToolBarAppearance enumeration: either Normal (the default) or Flat. When set to Normal, each toolbar button has a button-like raised edge. However, most applications favor the Flat style these days, where the toolbar appears completely flat, and the buttons have no outline except when the mouse is over them.

The ToolBar also controls where any text associated with a button appears through its TextAlign property. (A toolbar button may optionally have a text label, like the Back button on Internet Explorer.) This property’s type is the ToolBarTextAlign enumeration, and it can be either Right or Underneath. The default is Underneath.

The most important property of a toolbar is Buttons , whose type is ToolBarButtonCollection. This contains all the ToolBarButton objects on the toolbar. This is used in a similar way to the other collections we have seen, such as the MenuItems collection. As usual, items are added with the AddRange method, as shown in the following C# code:

this.toolBar1.Buttons.AddRange(

    new System.Windows.Forms.ToolBarButton[] {

        this.toolBarFileNew,

        this.toolBarFileOpen,

        this.toolBarFileSave});

Most of the interesting features of the buttons are managed through the ToolBarButton class itself, but there is one exception. Most buttons have images on them, and these images must be contained in an ImageList object. This is stored in the ToolBar object’s ImageList property. An image list is a collection of images all of equal size, gathered into a single resource for efficiency, and a toolbar has just one ImageList containing all the images required for the whole toolbar; individual buttons just specify indexes into this list. (Image lists are also used by the TreeView and ListView controls.)

Visual Studio .NET provides an editor for building image lists. It merges multiple bitmap files into a single long thin bitmap resource, which is the most efficient way of initializing an image list. The editor allows individual images to be removed or added, and for the list to be reordered. (Unfortunately, it won’t find all the places in your code where you referred to an image by its index, so exercise caution when reordering the images.)

Note that the buttons on a toolbar are not proper controls—the only control is the toolbar itself. Because of this, the ToolTip control will not be able to annotate individual toolbar buttons with the ToolTip extender property. Instead, the ToolBar class provides its own support for ToolTips—just set its ShowToolTips property to true. In the following section, we will see how to assign a ToolTip to each button, along with other button-specific properties.

The ToolBarButton Class

For each button contained in a ToolBar control, there is a corresponding object of class ToolBarButton. This turns out not to be a proper control—the class inherits from System.ComponentModel.Component, not Control. This is because in Windows, toolbars have always acted as single controls that provide the illusion of multiple buttons through careful redrawing and event handling to avoid creating too many controls.[18]

Toolbar buttons can have one of three appearances, determined by the Style property, which has the enumeration type ToolBarButtonStyle. This can be PushButton, which is a normal button. Or it can be ToggleButton, which looks the same as a normal button, except its state alternates between pushed and unpushed each time it is clicked. Or it can be a DropDownButton, in which case it should have a ContextMenu associated with its DropDownMenu property—with this style, the item will have a small downward-pointing arrow next to it, which will cause the context menu to be displayed. For all three styles, the exact appearance is determined by the parent ToolBar object’s Appearance property.

The Style property can also be set to Separator, in which case the item doesn’t behave like a button at all—it simply separates groups of other buttons.

You can specify which image the button contains with the ImageIndex property—this is an index into the containing ToolBar control’s image list. You can also display some text by setting the Text property. Remember that the location of the text (either beside or underneath the image) is controlled by the containing ToolBar, through its TextAlign property. (All buttons on a toolbar have the same text alignment.)

You can also provide ToolTip text for each button, through its ToolTipText property. This is essential if you want users to be able to learn what your buttons do without resorting to trial and error, unless your drawing skills are so good that you can convey any concept in a 15 × 15 pixel bitmap.

So we can now create toolbars and fill them with buttons. But as with menus, for this to be of any use, we must provide event handlers for when the buttons are clicked. The next section describes how to do this.

Event Handling

Handling events from toolbars is slightly inconvenient, because individual ToolBarButton objects do not raise events. Whenever the user clicks a button on a toolbar, the object that raises the event is the toolbar itself, through its ButtonClick event.

The ButtonClick event handler type is ToolBarButtonClickEventHandler. As usual, the first parameter is the sender of the event (the toolbar). The second is of type ToolBarButtonClickEventArgs, which contains a single property, Button. This is a reference to the ToolBarButton that was clicked. (There is also a ButtonDropDown event of the same type, which is raised for buttons whose style is DropDownButton.)

There is no direct way to associate a single handler method with a particular button. However, you can call the Buttons.IndexOf method on the toolbar to find the index of the button that was pressed—the buttons are numbered from left to right, starting at index 0. So you could handle these clicks with a switch statement, as shown in the C# code in Example 4-5, or with a Select Case statement, as shown in the VB code in Example 4-6.

Example 4-5. Simple toolbar button click handling in C#

private void InitializeComponent()

{

    . . .

    this.toolBar.ButtonClick +=

      new System.Windows.Forms.ToolBarButtonClickEventHandler(

 this.toolBar_ButtonClick);

    . . .

}



private void toolBar_ButtonClick(object sender,

    System.Windows.Forms.ToolBarButtonClickEventArgs e)

{

    switch(toolBar.Buttons.IndexOf(e.Button))

    {

        case 0:

  MessageBox.Show("New");

  break;



        case 1:

  MessageBox.Show("Open");

  break;

    }

}

Example 4-6. Simple toolbar button click handling in VB

Private Sub toolBar_ButtonClick(sender As Object, _

         e As System.Windows.Forms.ToolBarButtonClickEventArgs)

   Select Case toolBar.Buttons.IndexOf(e.Button)

      Case 0

         MsgBox("New")

      Case 1:

         MsgBox("Open")

   End Select

End Sub

However, because most toolbar buttons are directly equivalent to a menu item, you might find the unified technique described in the next section more convenient.



[18] This is because versions of Windows with strong 16-bit lineage such as Windows 98 and Windows ME have severe limitations on the number of controls that can be displayed at once. Until this code base finally dies out (which will probably not happen until a few years after the average desktop machine ships with a 64-bit processor as standard), these problems will still make their presence felt, through resource-conscious design decisions such as these.

Get .NET Windows Forms in a Nutshell now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.