I believe there's an old saying, "Clothes maketh the man", and this definitely applies to software too. No matter how clever and hard-working your applications are, if they're not wearing the latest well-designed clothes, people will think they are poorly written and out of date.
While working on a new project recently, I did a quick search on the web to see what the competition was up to. One of the features they had, which I didn't, was an Outlook-style menu bar, commonly referred to simply as an Outlook Bar. Deciding I wanted one too, I thought about writing my own. Searching the Code Project, I found two useful articles, Marc Clifton's An Outlook Bar Implementation, and Outlook XP bar by ACorbs. Both these articles were interesting and thought-provoking, and I downloaded each of them for a bit of a poke around, as one does!
I then found myself in a bit of a dilemma. I didn't want to simply copy someone else's code, but at the same time, I didn't want to spend hours and hours reinventing the wheel. I remembered a comment made by my manager at a previous job, many years ago. "What are we trying to do here? Achieve technical excellence, or get a job done?" Realising that Marc and ACorbs had done the former, I decided to go for the latter approach, and started doing some lateral thinking.
The eureka moment!
I proceeded to rummage around in the standard Windows Forms toolbox, and began to idly play around with splitters and panels. While doing this, I came across the
Dock property, which specifies the justification for a control. In other words, does it attach itself to the top, bottom, left or right of its container, or does it fill all the available space. An idea occurred to me, so I added a
Panel to my form, and added three
Buttons to the panel. I set the
Dock property of each button to
Top, and "Lo!", I had created an Outlook Bar!
Obviously, all I'd really done was stack three buttons one on top of the other, but they did resize themselves with the panel, which was decent of them. At this point, I realised I was going to have to write some code.
The only code I really needed is in the
Click event handler for the buttons. They all share a common handler, as shown here:
void ButtonClick(object sender, System.EventArgs e)
Button clickedButton = (Button)sender;
int clickedButtonTabIndex = clickedButton.TabIndex;
foreach (Control ctl in panel1.Controls)
if (ctl is Button)
Button btn = (Button)ctl;
if (btn.TabIndex > clickedButtonTabIndex)
if (btn.Dock != DockStyle.Bottom)
btn.Dock = DockStyle.Bottom;
if (btn.Dock != DockStyle.Top)
btn.Dock = DockStyle.Top;
case "Outlook Shortcuts":
case "Zip Files":
Basically, when any of the buttons on the panel is clicked, we save the clicked button and its
TabIndex, then go through all the controls on the panel in turn. If it's a button, we check the
TabIndex against that of the clicked button. If the
TabIndex is greater, then the current button must be below the clicked one, so we send it to the bottom by setting its
DockStyle.Bottom. If the
TabIndex is lower, then the button goes to the top.
At this stage, I should point out that to make this work, it's vital that the TabIndices of the buttons are set at design time to the correct order. In the supplied example, the "Cars", "Miscellaneous", "Zip Files" and "Outlook Shortcuts" buttons have their
TabIndex set to 1, 2, 3 and 4 respectively.
Back to the main plot. Having set the
Dock properties to send the buttons up and down, I noticed that all was not well. If I had buttons 1, 2, 3 and 4 at the top, and I clicked button 1, then buttons 2 to 4 went to the bottom, but they ended up in reverse order, like this:
In an attempt to correct this, I tried a few things, such as walking the panel's controls in reverse order, and altering the
TabIndex values "on the fly", but without success. I decided to research the
Dock property on MSDN, which told me about the z-order, and explained that it could be controlled by the
BringToFront methods of a control. It's explained here and here, much more clearly that I can do in a few words. Suffice to say, by calling the
SendToBack method on each button after I docked it, preserved the order of the buttons.
The last piece of the jigsaw was another standard Windows Control, the
ListView. I added this to the container panel, left its
View property as the default
LargeIcon, and set its
Dock property to
Fill, which means it will fill all the remaining space left by the buttons. I added some
ImageLists, threw together some code to populate the
ListView depending on which button was clicked, and I had a nice looking, functional Outlook bar, created from standard controls and a few lines of code. I then added a second
ListView to provide some basic functionality to demonstrate that the menu bar worked.
Hopefully, this article will be of interest, and possibly show how sometimes it's useful to look at a problem from a few different angles before getting your code editor out!