Accessibility
navigation | page content |
Accessibility
top of site | navigation |
Latest Tutorials
Tutorials

User control properties

In the latest C sharp tutorial, Huw Collingbourne adds browsable properties to his collapsible panel user control.

Last month, we began programming a collapsible panel control that can be installed into the toolbox of Visual Studio or another .NET IDE. In common with a standard panel, our control is able to ‘contain’ other controls. Unlike a standard panel, however, our control has the ability to collapse out of sight or expand to its full size when a button is clicked. In this way, it can reduce the clutter of a complex application by selectively hiding and showing groups of related controls.

Having laid the foundations for our collapsible panel control last month, we’ll now start building its superstructure. This largely involves adding properties to enable the user to make adjustments to the appearance and behaviour of the control at design time. For example, the user may want to display different text on the panel’s button when the panel is expanded and contracted. These properties appear in the appropriate categories listed in the Properties panel whenever one of our controls is dropped onto a form in the form-design workspace.

Load the TestCtrl2.sln solution and select the ‘Form1.cs [Design]’ tab to display the form design of our test application. We’ve already dropped two of our collapsible panel controls onto this form. Select one of these and look at the Properties panel. Make sure this displays the properties by category (in Visual Studio, you may need to click the ‘Categorized’ button at the top-left of the Properties panel) and you should see a category called ‘Control Button’. Beneath this is a group of properties to alter the appearance of the button docked to the top edge of the collapsible panel. Using these properties, you can change the font, style, colour and text of the button. You can also specify different button labels when the panel is expanded to full size (BtnTextExpanded), and when collapsed BtnTextCollapsed).

Most of the properties in the other categories are standard panel properties. However, you’ll find that we’ve also created some new properties in another custom category called ‘Panel’. This category contains properties to define the panel’s collapsed and expanded heights, and to set its initial state. If the Expand property is true, the panel will be expanded when the application runs, otherwise it will be collapsed. If you toggle the Expand property in the form designer, you’ll find that the state of the panel changes even at design time. The ScrollIncrement and ScrollSpeed properties are used to change the speed and smoothness of the expand/collapse animation. You may want to experiment with a few of these custom properties before taking a look at the code we’ve written to implement them.

Exposing button properties
Now look at the code in UserControl1.cs. This the code of the control. As explained last month, we initially created the control by selecting Windows Control Library from the New Project wizard. This enabled us to use the design workspace to create the basic layout of the control, and to add and position its control button. Having done this, we edited the code to make this class a descendant of Panel rather than of UserControl. This means that our control can now ‘contain’ other controls when they’re dropped onto it at design time. However, once we’ve changed the control’s ancestor, the visual layout no longer appears in the Design page. If you need to make alterations to the layout, you can edit the code to make the class descend from UserControl once again. Be careful when you do this, however, as UserControl and Panel have different sets of properties and you may cause unwanted side effects if you switch between the two classes. At any rate, be sure that your class descends from Panel before you compile it.

advertisement
Scroll down the code in this unit until you find the section headed by the comment, ‘Custom Properties’. The first property here is BtnTextExpanded, which is the text to be displayed on the control button when the panel is fully expanded. Using the standard property syntax, this has a pair of get and set accessors to return or assign values to a variable of the same type as the property itself. In this case, the type is string and the variable is called ebtntext. Normally, we might consider dispensing with a variable and using get and set to access the button’s own Text property, CtrlBtn.Text, directly. However, as the button displays different Text when the panel is collapsed, we use the variables, ebtntext and cbtntxt, to store the two alternative strings. The text displayed on the button when the panel is collapsed is accessed by our BtnTextCollapsed property.

You’ll notice that, just above each of these two properties, we define Description and Category attributes between square braces. In each case, the category is ‘Control Button’ so that this is the group beneath which the property appears in the Properties panel. The category doesn’t have to be user defined. If you enter the name of a standard category, the property will be appended to that group. The Description attribute defines a string such as ‘The Text displayed on the button when Panel is collapsed’. When the user selects the control’s property in the form design workspace, this string will appear at the bottom of the Properties panel.

The next few properties, BtnColor, BtnStyle, BtnHeight, BtnTextAlign, BtnFont and BtnTextColor, simply expose standard properties of the Button object. For example, BtnFont provides get and set accessors to the button’s Font property. The standard button properties will remain ‘hidden’ inside our CollapsiblePanel control unless we specifically expose them in this way.

Custom panel properties
Now we come to a set of properties belonging to the panel itself. The first of these, ExpandedHeight and CollapsedHeight, define the panel’s maximum and minimum vertical dimensions. By default, ExpandedHeight is the height of the panel as created in the form designer and CollapsedHeight is the height of the control button (plus a few pixels of ‘padding’ to allow for the height of the panel’s frame). This padding varies according to the frame’s BorderStyle, and the CollapsedHeight property allows for possible variations. Notice that the CollapsedHeight property has only a get accessor, but no set. This means our user won’t be able to set a value in the Properties panel. In fact, the values of both these properties are set in code, which means that neither of them needs to be visible in the Properties panel. If you want to hide these properties, their Browsable attributes must be set to false. You can do this by uncommenting this attribute in our code.

The next two properties, ScrollSpeed and ScrollIncrement, determine the speed and smoothness at which the panel expands and contracts. ScrollSpeed permits each panel resizing operation to be performed at intervals between one and 200ms. ScrollIncrement permits the panel to be resized in increments of between one and 5,000 pixels. If the user enters a value outside these ranges, the value is automatically ‘corrected’. ScrollSpeed defines the tick interval of the Timer. At each interval, the timer1_Elapsed() method expands or contracts the panel in increments defined by ScrollIncrement.

Sliding controls The next property, Expand, sets the initial state of the Panel. When a true value is set, the Panel is expanded, otherwise it’s contracted. The code here is straightforward, though you need to pay attention to the call to the DoAnchorControls() method when the panel is set to its collapsed state. If the Controls on the panel are anchored to the bottom (see ‘Anchoring controls’), they’ll scroll up and down as the panel itself scrolls. If they’re not so anchored, the controls will appear to remain stationary as the panel slides up and down over them like a curtain. Our DoAnchorControls() method applies the anchor style specified by the variable, _ctrlanchor, to each control on the panel (with the exception of the button, CtrlBtn, which is always anchored to the top of the panel).

The addition of these properties has transformed the awkward control we created last month into a control much more at home in the visual form designer of the IDE. We now have a collapsible panel that can be recoloured, resized and restyled, and the speed and smoothness of its animation can be fine-tuned.

The aim of this control is to provide a neat way of simplifying your user interfaces by creating themed groups of controls – one group per panel – which can be selectively hidden. There are, of course, other ways of accomplishing this using the standard .NET controls, as explained elsewhere in this month’s column. However, the advantage of our collapsible panel is that it can potentially organise a complex interface within just one small ‘button bar’, with multiple panels grouped beneath one another, or even placed inside other ‘container’ panels. There’s still plenty we can do to improve on our collapsible panel control, and we’ll add the finishing touches next month.

Anchoring controls
How can a panel set the properties of the controls it contains? Here’s our solution…

One of the design objectives of our collapsible panel control was to enable the user to decide whether controls contained within the panel should move with the panel itself, or remain static. To understand this difference, press F5 to run the TestApp project in the TestCtrl2.sln solution. Click the control buttons at the top of each of the two panels and observe what happens to the two buttons contained inside the panels.

The panel on the left appears to slide over the buttons, while the buttons themselves don’t move. The buttons on the right-hand panel, however, slide in unison with the panel. The effect is that the left-hand panel is like a curtain that is drawn over the buttons.

The behaviour of the buttons is defined by their Anchor properties. An Anchor property can be set to Top, Bottom, Left, Right or any combination of those four values. When this property includes the Top anchor, the object moves in unison with the top of the containing control.

While it would be possible for the user to set the anchors for each object placed onto a Collapsible Panel at design time, this would be a time consuming process. We decided to add an AnchorControls property to the panel, so that our user can set this single property in order to anchor all the contained controls.

The problem here is that each instance of our Collapsible Panel will contain different sets of controls and the panel has no way of knowing which controls it contains until the application is run. Our solution to this problem is to perform some last minute initialisation when the control first becomes visible. This includes setting the anchors of all the controls using our DoAnchorControls() method.
Huw Collingbourne  
  PC Plus Issue 224 - Christmas 2004