RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Gain Design-Time Power with Control Editors, Part 2 of 2

Learn how to add custom editing dialogs, smart tags, and property pages to your controls.

he first part of this article provided a detailed description of a StateSelector control that lets users select a state from a map. The map itself is a control property named Map. In the Visual Studio Properties window, the article showed how to use a type converter to display a special representation of the Map property in the Properties window. Specifically, that type converter displays the Map property as the string (none) when the property is Nothing or (map) when it contained a value. Part 1 also showed how to use a file name editor to let users select a file, and how to use a dropdown editor to let users pick a line style from a list.

While those features are uncommon, you can go far beyond that. For example, you can display a custom dialog editor that lets users set complicated properties that require more interaction than a dropdown. You can also add smart tags and property pages to your controls, allowing users to set multiple properties in even more complex ways.

Selected Property Dialog
The StateSelector control's Selected property determines the states that are currently selected on the map. This property represents the selected states using a comma-separated list of their abbreviations. For example, you can set the Selected property to "CA,NV,UT,CO,AZ,NM" to select the states highlighted in Figure 1.

Figure 1. Selected States: The StateSelector control's Selected property determines which states are selected.
Setting the Selected property textually works, but it is somewhat cumbersome. Imagine instead letting users set the property graphically—by clicking on the states in a dialog such as Figure 1. Not only is selecting states in this manner more intuitive, but it's also less error prone, and lets users easily see mistakes in the pattern of selected states.

The first part of this article showed how to use an editor class to display a dropdown list for the StateSelector control's LineStyle property. You can use a similar technique to display an editing dialog. As before, you begin the process by adding attributes to the property declaration. The following code shows how the StateSelector control defines its Selected property:

   Public Property Selected() As String
         If m_Map Is Nothing Then Return ""
         Dim txt As String = ""
         For Each map_state As MapState In m_Map.MapStates
            If map_state.Selected Then txt &= "," & map_state.Name
         Next map_state
         ' Remove leading comma.
         If txt.Length > 0 Then txt = txt.Substring(1)
         Return txt
      End Get
      Set(ByVal value As String)
         If m_Map Is Nothing Then Exit Property
         value = "," & value.ToUpper & ","
         For Each map_state As MapState In m_Map.MapStates
            map_state.Selected = _
               value.Contains("," & map_state.Name.ToUpper & ",")
         Next map_state
      End Set
   End Property
The property's Editor attribute indicates that the Properties window can use the SelectedEditor class to edit Selected values.

The control delegates the property to the MapState objects displayed by the map. The Get portion of the property iterates through the selected MapState objects and builds a comma-delimited list of states abbreviations. The Set portion loops through the MapState objects and selects those whose abbreviations appear in the value string parameter.

Listing 1 shows how the SelectedEditor class works. When a user clicks on the ellipsis to the right of the Selected property in the Properties window, Visual Studio creates an instance of the SelectedEditor class and uses that to edit the Selected property value.

SelectedEditor inherits from UITypeEditor and then overrides key methods to do its important work. The GetEditStyle function returns Modal to indicate that the editor is a modal dialog.

The EditValue function in Listing 1 does the actual editing. It starts by getting a reference to an editor service that it can use to control the editing dialog, and then obtains a reference to the StateSelector control being edited. If the StateSelector does not have a map loaded, the function displays an error message and exits.

Next, EditValue creates a new dlgEditSelected form containing OK and Cancel buttons and a StateSelector control, which shows the selected states and lets the user modify the selection, as shown in Figure 1. (I like the symmetry of using a StateSelector control to edit a StateSelector control.)

The code sets the dialog's StateSelector control's Map property to a cloned copy of the Map property used by the control it is editing. This is an important point. If the code were to set the dialog control's Map property equal to the editing control's Map property, then the two would be references to the same StatesMap object. In that case, any changes you made to the editing dialog would immediately affect the control you were editing so you could not use the Cancel button to discard them. But because the code uses a clone, the dialog has its own copy, and users can save or discard their changes depending on which button they click.

The code calls the dialog's SetSize method, which resizes the dialog to fit the StateSelector control.

Finally the EditValue function displays the dialog modally and examines the returned result. If the user clicked the OK button, the EditValue function returns the new cloned copy of the Map property with the user's changes. If the user clicked Cancel, the function returns the original Map property value. In either case, the Properties window sets the edited control's Map property to the value returned by EditValue.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date