A compound control provides a visible interface that consists of multiple Windows controls. The controls that make up a compound control are known as constituent controls. As a result, this type of control doesn’t inherit the functionality of any specific control. You must implement its properties and methods with custom code. This isn’t as bad as it sounds, because a compound control inherits the UserControl object, which exposes quite a few members of its own (the Anchoring and Docking properties, for example, are exposed by the UserControl object, and you need not implement these properties — thank Microsoft). You will add your own members, and in most cases you’ll be mapping the properties and methods of the compound controls to a property or method of one of its constituent controls. If your control contains a TextBox control, for example, you can map the custom control’s WordWrap property to the equivalent property of the TextBox. The following property procedure demonstrates how to do it:
You don’t have to maintain a private variable for storing the value of the custom control’s WordWrap property. When this property is set, the Property procedure assigns the property’s value to the TextBox1.WordWrap property. Likewise, when this property’s value is requested, the procedure reads it from the constituent control and returns it. In effect, the custom control’s WordWrap property affects directly the functionality of one of the constituent controls.
The same logic applies to events. Let’s say your compound control contains a TextBox and a ComboBox control, and you want to raise the TextChanged event when the user edits the TextBox control, and the SelectionChanged event when the user selects another item in the ComboBox control. First, you must declare the two events:
Event TextChanged Event SelectionChanged
Then, you must raise the two events from within the appropriate event handlers: the Text-Changed event from the TextBox1 control’s TextChanged event handler, and the SelectionChanged event from the ComboBox1 control’s SelectedIndexChanged event handler:
Private Sub TextBox1_TextChanged(...) _ Handles FocusedTextBox1.TextChanged RaiseEvent TextChanged() End Sub Private Sub ComboBox1_SelectedIndexChanged(...) _ Handles ComboBox1.SelectedIndexChanged RaiseEvent SelectionChanged() End SubCode language: CSS (css)
The ColorEdit Control Example
In this section, you’re going to build a compound control that’s similar to the Color dialog box (Download the project files). The ColorEdit control allows you to specify a color by adjusting its red, green, and blue components with three scroll bars, or to select a color by name. The control’s surface at runtime on a form is shown in Figure 8.4.
Create a new Windows Control Library project, the ColorEdit project. Save the solution and then add a new Windows Application project, the TestProject, and make it the solution’s startup project, just as you did with the first sample project of this chapter.
Now open the UserControl object and design its interface, as shown in Figure 8.4. Place the necessary controls on the UserControl object’s surface and align them just as you would do with a Windows form. The three ScrollBar controls are named RedBar, GreenBar, and BlueBar, respectively. The Minimum property for all three controls is 0; the Maximum for all three is 255. This is the valid range of values for a color component. The control at the top-left corner is a Label control with its background color set to Black. (We could have used a PictureBox control in its place.) The role of this control is to display the selected color.
The ComboBox at the bottom of the custom control is the NamedColors control, which is populated with color names when the control is loaded. The Color class exposes 140 properties, which are color names (Beige, Azure, and so on). Don’t bother entering all the color names in the ComboBox control; just open the ColorEdit project and you will find the AddNamedColors() subroutine, which does exactly that.
The user can specify a color by sliding the three ScrollBar controls or by selecting an item in the ComboBox control. In either case, the Label control’s Background color will be set to the selected color. If the color is specified with the ComboBox control, the three ScrollBars will adjust to reflect the color’s basic components (red, green, and blue). Not all possible colors that you can specify with the three ScrollBars have a name (there are approximately 16 million colors). That’s why the ComboBox control contains the Unknown item, which is selected when the user specifies a color by setting its basic components.
Finally, the ColorEdit control exposes two properties: NamedColor and SelectedColor. The NamedColor property retrieves the selected color’s name. If the color isn’t selected from the ComboBox control, the value Unknown will be returned. The SelectedColor property returns or sets the current color. Its type is Color, and it can be assigned any expression that represents a color value. The following statement will assign the form’s BackColor property to the SelectedColor property of the control:
UserControl1.SelectedColor = Me.BackColor
You can also specify a color value with the FromARGB method of the Color object:
UserControl1.SelectedColor = Color.FromARGB(red, green, blue)
The implementation of the SelectedColor property (shown in Listing 8.3) is straightforward. The Get section of the procedure assigns the Label’s background color to the SelectedColor property. The Set section of the procedure extracts the three color components from the value of the property and assigns them to the three ScrollBar controls. Then it calls the ShowColor subroutine to update the display. (You’ll see shortly what this subroutine does.)
Listing 8.3: SelectedColor Property Procedure
The NamedColor property (see Listing 8.4) is read-only and is marked with the ReadOnly keyword in front of the procedure’s name. This property retrieves the value of the ComboBox control and returns it.
Listing 8.4: NamedColor Property Procedure
When the user selects a color name in the ComboBox control, the code retrieves the corresponding color value with the Color.FromName method. This method accepts a color name as an argument (a string) and returns a color value, which is assigned to the namedColor variable. Then the code extracts the three basic color components with the R, G, and B properties. (These properties return the red, green, and blue color components, respectively.) Listing 8.5 shows the code behind the ComboBox control’s SelectedIndexChanged event, which is fired every time a new color is selected by name.
Listing 8.5: Specifying a Color by Name
Private Sub ComboBox1_SelectedIndexChanged(...) _ Handles ComboBox1.SelectedIndexChanged Dim namedColor As Color Dim colorName As String colorName = ComboBox1.SelectedItem If colorName <> "Unknown" Then namedColor = Color.FromName(colorName) HScrollBar1.Value = namedColor.R HScrollBar2.Value = namedColor.G HScrollBar3.Value = namedColor.B ShowColor() End If End SubCode language: PHP (php)
The ShowColor() subroutine simply sets the Label’s background color to the value specified by the three ScrollBar controls. Even when you select a color value by name, the control’s code sets the three ScrollBars to the appropriate values. This way, we don’t have to write additional code to update the display. The ShowColor() subroutine is quite trivial:
Sub ShowColor() Label1.BackColor = Color.FromARGB(255, HScrollBar1.Value, _ HScrollBar2.Value, HScrollBar3.Value) End Sub
The single statement in this subroutine picks up the values of the three basic colors from the ScrollBar controls and creates a new color value with the FromARGB method of the Color object. The first argument is the transparency of the color (the A, or alpha channel), and we set it to 255 for a completely opaque color. You can edit the project’s code to take into consideration the transparency channel as well. If you do, you must replace the Label control with a PictureBox control and display an image in it. Then draw a rectangle with the specified color on top of it. If the color isn’t completely opaque, you’ll be able to see the underlying image and visually adjust the transparency channel.
Testing the ColorEdit Control
To test the new control, you must place it on a form. Build the ColorEdit control and switch to the test project (add a new project to the current solution if you haven’t done so already). Add an instance of the new custom control to the form. You don’t have to enter any code in the test form. Just run it and see how you specify a color, either with the scroll bars or by name. You can also read the value of the selected color through the SelectedColor property. The code behind the Color Form button on the test form does exactly that (it reads the selected color and paints the form with this color):
Private Sub Button1_Click(...) Handles Button1.Click Me.BackColor = ColorEdit1.SelectedColor End SubCode language: PHP (php)