Taking Control of Overflow Menus

As you saw at the beginning of this chapter (in Figure 14-1), the ToolStrip uses an overflow menu when there isn't enough room to show all the buttons at once. By default, items are dropped off the end of the ToolStrip and added into the overflow menu. But more sophisticated programs that use overflow menus (like Microsoft Office) take a different approach— they selectively eliminate commands that are deemed to be less important. You can implement the same sort of logic with the .NET ToolStrip. In fact, there are several options, depending on how much control you want.

At the highest level, you can prevent items from being placed in an overflow menu by setting the ToolStripItem.Overflow to Never (the default value is AsNeeded). A ToolStripItem configured in this way will remain on the ToolStrip as other AsNeeded items are dropped into the overflow menu. If there are several items set to not overflow and the ToolStrip can't accommodate all of them, the items just won't appear at all. You have one other choice—if you set ToolStripItem.Overflow to Always the item will remain permanently in the overflow menu, regardless of how much space there is.

In some situations, you might want even more fine-grained control. For example, maybe you want to show image and text buttons when space allows, but remove the text captions when the ToolStrip shrinks to prevent the need for an overflow menu. The basic technique is to react to the ToolStrip.LayoutCompleted event, which fires after all the items have been arranged and the overflow menu has been created. You then have two possibilities for determining what items overflowed.

Your first option is to check the ToolStrip.OverflowButton property to get access to the overflow menu. You can test its HasDropDownItems property to check whether there is anything in the overflow menu. Alternatively, you can loop through the ToolStrip.Items collection (which still contains all the items) and check the ToolStripItem.Placement property of each item. If it returns ToolStripItemPlacement.Overflow, this item has been relocated to the overflow menu.

This task is conceptually quite straightforward, although in practice the code can become quite convoluted. The following example implements a basic approach to custom overflow menus. If possible, it tries to fit all buttons with text and images. If that doesn't work, it takes the first button on the right and switches the display style to text-only. As the ToolStrip continues to shrink, it removes all the images one-by-one. If you shrink the ToolStrip beyond this point, it starts switching the text-only buttons to the even more compact image-only display (see Figure 14-20). The same logic unfolds in reverse when you expand the ToolStrip.

3 CustomOverflow

y CustomOverflow

H CustomOverflow

Figure 14-20. Advanced ToolStrip configuration at runtime

To implement this design, you need to handle two ToolStrip events: Layout and LayoutCompleted. The LayoutCompleted event fires when the layout has been finished and the overflow menu has been created. At this point, you can check to see if an overflow menu exists. If it does, you can try selectively reducing the buttons to a smaller display format.

private void toolStripOverflow_LayoutCompleted(object sender, EventArgs e) {

// Check if the overflow menu is in use.

if (toolStrip1.OverflowButton.HasDropDownItems) {

// Step backwards.

for (int i = toolStripl.Items.Count - 1; i >= 0; i--)

ToolStripltem item = toolStrip1.Items[i];

if (!(item is ToolStripSeparator)) {

if (item.DisplayStyle == ToolStripltemDisplayStyle.ImageAndText) {

item.DisplayStyle = ToolStripItemDisplayStyle.Text; return;

// If we reached here, all buttons are shrunk to text. // Try reducing them further.

for (int i = toolStripl.Items.Count-1; i >= 0; i--)

ToolStripItem item = toolStrip1.Items[i];

if (!(item is ToolStripSeparator)) {

if (item.DisplayStyle == ToolStripItemDisplayStyle.Text) {

item.DisplayStyle = ToolStripItemDisplayStyle.Image; return;

// If we reach here, the bar is fully collapsed.

The Layout event fires at the beginning of the resize process. At this point, you can attempt to expand the ToolStrip if space allows. Here's the code:

private void toolStripOverflow_Layout(object sender, LayoutEventArgs e) {

if (toolStrip1.DisplayRectangle.Width > MeasureToolStrip()) {

// Right now everything fits.

// Check if a larger size is appropriate.

foreach (ToolStripItem item in toolStrip1.Items) {

if (!(item is ToolStripSeparator)) {

// Look to expand any image-only buttons.

if (item.DisplayStyle == ToolStripItemDisplayStyle.Image) {

item.DisplayStyle = ToolStripItemDisplayStyle.Text; return;

// If we reach here, there are no image-only buttons.

// Look to expand any text-only buttons.

foreach (ToolStripItem item in toolStrip1.Items)

if (!(item is ToolStripSeparator))

if (item.DisplayStyle == ToolStripItemDisplayStyle.Text) {

item.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; return;

// If we reach here, the bar is fully expanded.

Although this design works, it does have a few idiosyncrasies. It the user jerks the border quickly enough, the ToolStrip size can be collapsed dramatically without the Layout and LayoutCompleted events firing enough times to update all the buttons. The result is that all the buttons won't be resized and an overflow menu will be present. A more sophisticated implementation would need to calculate the available space and determine which buttons to expand, and it would take dramatically more code.

+1 0

Responses

  • simone
    Why won't toolstrip button set asneeded go to overflow?
    1 year ago

Post a comment