- 7.1 A Survey of .NET Windows Forms Controls
- 7.2 Button Classes, Group Box, Panel, and Label
- 7.3 PictureBox and TextBox Controls
- 7.4 ListBox, CheckedListBox, and ComboBox Classes
- 7.5 The ListView and TreeView Classes
- 7.6 The ProgressBar, Timer, and StatusStrip Classes
- 7.7 Building Custom Controls
- 7.8 Using Drag and Drop with Controls
- 7.9 Using Resources
- 7.10 Summary
- 7.11 Test Your Understanding
7.7 Building Custom Controls
At some point, you will face a programming task for which a standard WinForms control does not provide the functionality you need. For example, you may want to extend a TextBox control so that its background color changes according to its content, group a frequently used set of radio buttons into a single control, or create a new control that shows a digital clock face with the date underneath. These needs correspond to the three principal types of custom controls:
- A control that derives from an existing control and extends its functionality.
- A control that can serve as container to allow multiple controls to interact. This type of control is referred to as a user control. It derives directly from System.Windows.Forms.UserControl rather than Control, as do standard controls.
- A control that derives directly from the Control class. This type of control is built "from scratch," and it is the developer’s responsibility to draw its GUI interface and implement the methods and properties that allow it to be manipulated by code.
Let’s now look at how to extend an existing control and create a user control.
Extending a Control
The easiest way to create a custom control is to extend an existing one. To demonstrate this, let’s derive a TextBox that accepts only digits. The code is quite simple. Create a new class NumericTextBox with TextBox as its base class. The only code required is an event handler to process the KeyPress event and accept only a digit.
class NumericTextBox: TextBox { public NumericTextBox() { this.KeyPress += new KeyPressEventHandler(TextBoxKeyPress); } protected void TextBoxKeyPress(object sender, KeyPressEventArgs e) { if (! char.IsDigit(e.KeyChar)) e.Handled = true; } }
After the extended control is compiled into a DLL file, it can be added to any form.
Building a Custom UserControl
Think of a user control as a subform. Like a form, it provides a container surface on which related widgets are placed. When compiled, the entire set of controls is treated as a single user control. Of course, users still can interact directly with any of the member controls. Programmatic and design-time access to control members is available through methods and properties defined on the user control.
The easiest way to design a control is with an IDE such as Visual Studio.NET (VS.NET), which makes it easy to position and size controls. The usual way to create a user control in VS.NET is to open a project as a Windows Control Library type. This immediately brings up a control designer window. The design window can also be accessed in a Windows Application by selecting Project – Add User Control from the top menu bar or right-clicking on the Solution Explorer and selecting Add – Add User Control. Although VS.NET can speed up the process of creating a control, it does not generate any proprietary code that cannot be duplicated using a text editor.
A UserControl Example
As an example, let’s create a control that can be used to create a questionnaire. The control consists of a label whose value represents the question, and three radio buttons contained on a panel control that represent the user’s choice of answers. The control exposes three properties: one that assigns the question to the label, one to set the background color of the panel control, and another that identifies the radio button associated with the user’s answer.
Figure 7-16 shows the layout of the user control and the names assigned to each contained control.
Here is how the members are represented as fields within the UserControl1 class:
public class UserControl1 : System.Windows.Forms.UserControl { private Panel panel1; private RadioButton radAgree; private RadioButton radDisagree; private RadioButton radUn; private Label qLabel;
Figure 7-16 Layout of a custom user control
Listing 7-6 contains the code for three properties: SetQ that sets the label’s text property to the question, PanelColor that sets the color of the panel, and Choice, which returns the answer selected by the user as a Choices enum type.
Listing 7-6 Implementing Properties for a Custom User Control
public enum Choices { Agree = 1, DisAgree = 2, Undecided = 3, } public string SetQ { set {qLabel.Text = value;} get {return(qLabel.Text);} } public Color PanelColor { set {panel1.BackColor= value;} get {return(panel1.BackColor);} } public Choices Choice { get { Choices usel; usel = Choices.Undecided; if (radDisagree.Checked) usel= Choices.DisAgree; if (radAgree.Checked) usel = Choices.Agree; return(usel);} } }
Using the Custom User Control
If the user control is developed as part of a VS.NET Windows Application project, it is automatically added to the tool box under the Windows Forms tab. Simply select it and drop it onto the form. Otherwise, you have to right-click on a tool box tab, select Customize ToolBox, browse for the control, and add it to the tool box.
Figure 7-17 Custom user controls on a form
Figure 7-17 provides an example of using this new control. In this example, we place two control instances on the form and name them Q1 and Q2:
private usercontrol.UserControl1 Q1; private usercontrol.UserControl1 Q2;
The properties can be set in the constructor or at runtime in the Form.Load event handler. If using VS.NET, the properties can be set at design time using the Property Browser.
Q1.SetQ = "The economy is performing well"; Q2.SetQ = "I’m not worried about the budget deficit."; Q1.PanelColor = Color.Beige;
The final step in the application is to do something with the results after the questionnaire has been completed. The following code iterates through the controls on the form when the button is clicked. When a UserControl1 type is encountered, its Choice property is used to return the user’s selection.
private void button1_Click(object sender, System.EventArgs e) { foreach (Control ct in this.Controls) { if (ct is usercontrol.UserControl1) { UserControl1 uc = (UserControl1)ct; // Display control name and user’s answer MessageBox.Show(ct.Name+" "+ uc.Choice.ToString()); } } }
Working with the User Control at Design Time
If you are developing an application with VS.NET that uses this custom control, you will find that the Property Browser lists all of the read/write properties. By default, they are placed in a Misc category and have no description associated with them. To add a professional touch to your control, you should create a category for the control’s events and properties and add a textual description for each category member.
The categories and descriptions available in the Property Browser come from metadata based on attributes attached to a type’s members. Here is an example of attributes added to the PanelColor property:
[Browsable(true), Category("QControl"), Description("Color of panel behind question block")] public Color PanelColor { set {panel1.BackColor = value;} get {return (panel1.BackColor);} }
The Browsable attribute indicates whether the property is to be displayed in the browser. The default is true. The other two attributes specify the category under which the property is displayed and the text that appears below the Property Browser when the property is selected.
Always keep in mind that the motive for creating custom user controls is reusability. There is no point in spending time creating elaborate controls that are used only once. As this example illustrates, they are most effective when they solve a problem that occurs repeatedly.