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.
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.
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.
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.