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
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
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
' Remove leading comma.
If txt.Length > 0 Then txt = txt.Substring(1)
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 & ",")
The property's Editor
attribute indicates that the Properties window can use the SelectedEditor class to edit Selected
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
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
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.
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.
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