Create a collapsible panel
When you create a complex application, chances are you’ll end up with a complex user interface with dozens, or even hundreds of separate buttons and controls scattered across numerous toolbars, forms and dialog boxes. In an attempt to impose some order on this chaos, application developers often group related controls onto tabbed pages. For example, if you select Tools | Options in Microsoft Word, you’ll be presented with a dialog containing up to a dozen tabbed pages. There are, however, alternatives to tabs and we’ll look at some of them this month.
In recent years, several software companies have championed new ways of organising controls into easy to use groups. Macromedia and Adobe use collapsible panels to group controls, icons and options in their graphic and web design applications. The animation program 3D Studio Max uses collapsible group boxes, while the form designer in Microsoft Visual Studio uses the Toolbox to arrange sets of controls on vertically sliding panels.
Before getting into detailed coding, we have to decide on precisely the type of collapsible or scrollable control we want to develop. While we don’t plan to create a slavish copy of the user interface elements found in commercial software (these are frequently patented and we really can’t afford the legal fees!), we would like to adopt some of their essential features. In particular, we’d like to have some way of hiding and revealing groups of controls with the click of a mouse.
Hide and seek
Load up the Test.sln solution. You’ll see that I’ve created a form containing two panels, each of which has a button at the top and a random selection of labels and text underneath. The label and text controls represent any arbitrary group of controls that we want to be able to hide and show by clicking the button. Run the program and try it out.
First, click the button in the left-hand panel. You’ll see that this scrolls downwards, taking the grouped controls with it and revealing some other controls previously hidden. Click the button again and it scrolls back to its original position. In essence, this is a simple attempt at a Visual Studio-like scrolling Toolbox. Next, click the button on the second panel. This time, the button stays where it is and the panel itself collapses beneath it, hiding all the controls. Click it a second time and the panel expands to its original side and once again reveals the controls.
In their present form, neither of these panels has anything more than a basic set of features. Moreover, they’re both hard-coded into this specific project’s code, so they’re not easily reused. In short, this project is no more than a programming ‘scratchpad’ where I’ve tried a few experiments in order to get a very rough idea of how the controls might look and work. Before proceeding to develop one of these further, let’s see what’s going on behind the scenes.
Clock and scroll
Double-click the left-hand button to find the button1_Click() method in the editor. You’ll see that this does nothing more than set a 1ms interval for the timer1 control, and call its Start() method to set it ticking. The timer is shown as a little clock icon beneath the form design and it’s not visible during program execution. The real work is done in the timer1_Tick() method which executes with each tick of the timer. Incidentally, a 1ms interval is somewhat theoretical and there’s no guarantee that .NET will give sufficient priority to timer events to process ticks at this rate. If you set the interval from one to 10, you’ll find that the animation controlled by timer ticks doesn’t run 10 times slower!
Incidentally, there are Timer objects available on both the Windows Forms and the Components pages of the Visual Studio Toolbox. Either of these can be used in a project. Our timer1 is the Windows Forms timer, while timer2 is the Components timer. The most important difference between the two Timers is that the one from the Components palette responds to an Elapsed event rather than to a Tick event. For a discussion of these Timers, refer to the section called ‘The Three Timers’.
Our scrollable panel, OuterPanel, contains a second panel, InnerPanel, that contains both the ‘Click Me’ button and a third panel on which the various controls have been placed. When timer1 responds to each Tick event in timer1_Tick(), it moves the InnerPanel up or down depending on whether the Boolean atTop variable is True or not, as it is when button1 is at the top of the panel. It moves InnerPanel down in 10-pixel increments until its Top position is no longer less than a value stored in the endpos variable. When the button is at the bottom of the panel, InnerPanel is moved up in 10-pixel increments until its Top is no longer greater than the value of startpos. You can see how the values of startpos and endpos are initialised in Form1_Load(). As a bit of added window dressing, we’ve added an up arrow or down arrow character to the small arrowbtn control.
A state of collapse
Now look at the panel on the right. This one implements a collapsible group that rolls itself upwards and downwards like a Venetian blind. Once again, all the real work is done by the Timer. When the panel, CollapsePanel, is in its expanded state, the timer2_Elapsed() method reduces its height in increments of 10 pixels per Elapsed event until there are no more than 10 pixels left to go:
if (CollapsePanel.Height >(ContractedHeight+10)) CollapsePanel.Height -=10;At this point, the else clause executes and sets the panel height to an exact value, previously saved in the Contracted Height variable:
CollapsePanel.Height = ContractedHeight;You may wonder why we add 10 to ContractedHeight in the if clause. This is to allow for the fact that the panel height may not be divisible by 10. If we failed to add 10 in the if test, the panel could expand beyond the height defined by ContractedHeight and would seem to ‘bounce’ as we finally resize it. Our code avoids this bounce. The code that executes when the panel resizes is broadly similar. Once again, the ExpandedHeight and ContractedHeight values are assigned in Form1_Load().
Building a control
We slightly prefer the collapsible group to the scrollable panel and so we’ve decided to turn this into a reusable control. To create a control, we need to start a new Windows Control Library project. In order to be able to test the control as we go along, it’s a good idea to add a regular Windows Application project to the solution. We’ve done this in the TestCtrl.sln solution.
The control was designed in the form design workspace and coded in the editor as normal. You probably won’t be able to see the visual design of the control. We’ll explain why this is in a moment. First, look at the code. It’s broadly similar to the code in our last project apart from the fact that we make adjustments to the control itself (using the keyword, this) rather than to a specific panel. We’ve also added two properties, ButtonText and ContractedButtonText, which will appear in the Properties panel and enable the user to assign different text for the default expanded state and the collapsed state.
The main problem with the control designer is that the resulting UserControl can’t have other controls dragged onto it at design time. But this is a necessary requirement of our control. After all, this is meant to be an expandable control group. Necessarily, therefore, the programmer will want to be able to place controls onto it!
We’ve used a dirty but effective hack to accomplish this. Having designed the user control, we’ve changed the class definition to make it descend from the Panel class rather than the UserControl class. This means that you can now drop other controls on to it in the form designer. However, the control’s visual design is no longer accessible. The moral is: don’t change the control’s ancestor until you’ve finished designing it! Your new control should now appear on the ‘My User Controls’ page of the Toolbox. You can drop it onto the form of any projects in the current solution, or you can install it for future use into a page of the Toolbox, as explained in the section called ‘Installing User Controls’. In the current solution, you’ll see that we’ve already added some of our scrollable panel controls to the TestApp project. Refer to ‘Using Scrollable Panels’ for more information.
In this month’s project, we’ve created a reusable control with remarkably little programming effort. However, while it may work quite well, it doesn’t really look that good. Next month, we’ll attempt to give our control a thorough makeover.
Give some of our controls a trial run to see how they can simplify a user interface
You can see our CollapsiblePanel controls in the TestApp application that forms part of the TestCtrl solution. Make sure TestApp is the start-up project. You can do this by right-clicking its name in the Solution Explorer and making a selection from the pop-up menu before running run the application.
We’ve used multiple instances of the CollapsiblePanel control. Each contains a number of standard Windows Form controls, such as buttons and text boxes. Moreover, some CollapsiblePanel controls even contain other CollapsiblePanel controls. For example, on the left of the form, you can see that the Options panel contains an Advanced Options panel. The user can click the button at the top of either of these panels to scroll it out of sight and reveal the underlying panel. The Advanced Options panel even contains a Tab control, one page of which contains yet another CollapsiblePanel control. And, just to round the whole thing off, the entire set of controls has been placed inside one big CollapsiblePanel. Click the horizontal grey button towards the top of the form to scroll everything out of sight.
While this application doesn’t do anything useful, it does illustrate how our CollapsiblePanel control might be used selectively to hide the clutter of a complex application, or a dialog box containing numerous options. Notice that when you select a CollapsiblePanel control on the form, the Properties page lets you adjust all the standard panel properties, such as BackColor and BorderStyle.
You may also notice that any controls contained by a Collapsible Panel appear to remain in their original position as the panel scrolls up and down. If you prefer the controls to slide up and down with the panel itself, change their Anchor properties from the default Top, Left to Bottom, Left. They’ll then scroll in parallel with the bottom of the panel. We’ve set this property for the Tab control on the Advanced Options panel.

