Adding Your Own Control
Now that you have some background on the basic customization features, how do you add your own controls? For the most part, the process is no different from creating any user control.
Don't you wish you could just have a simple control that automatically formatted a TextBox for phone number entries? In Visual Studio 2003, this was quite a bit more complex. In Visual Studio 2005, it's easier. Using the new MaskedTextBox control you can simply map the HomePhone
column to this control and manually set the Mask
property each time, but even that's a pain. If I decide I want to change all my formatting from (999) 867-5309 to 999.867.5309, I'd have to go to each and every form and change the mask. Besides, this is a nice simple control. I'm sure you'll have more complex examples that will work just as well.
|The DataConnector/BindingSource can turn a single object into a list.|
Let's start by creating a PhoneBox control. Add a new Control Library to your solution. Creating a separate project is important because you want this control to show up in your custom list all the time. Once you make this control a project default, subsequent projects will need to find the assembly. It's best to save your DLL in a safe, common location. You don't need to GAC it, 'cause that's just evil. Now add the code from Listing 2
to your project. Build the project so that the PhoneBox control compiles successfully. The key is to verify your PhoneBox shows up on the Toolbox, as in Figure 3
. You may need to select Rebuild All to get it to "kick in."
Magic in the Toolbox?
If you remember using the Tools>Options dialog box for control customization, you may have noticed that not all controls were displayed. When we were trying to figure out how to filter the appropriate controls, we wanted to leverage something that already existed. Searching the entire hard drive, or requiring registration in the GAC (the better but still evil replacement for DLL hell),
just didn't seem like a reasonable limitation. We decided to leverage the controls in the Toolbox, figuring this is where you'd likely place them anyway. When the Tools>Options dialog box loads, it iterates through all the controls in the Toolbox and loads any control that has one of three new binding attributes described later. This is why you need to make sure the PhoneBox shows up in the Toolbox.
So how do you proceed? You guessed it. Go to the Tools>Options dialog box and add your PhoneBox to the String data type. With that done, you can now go to the Data Sources Window and change the default control for Employee.HomePhone
So that sums up the simplistic model for custom controls. If you inherit from one of the .NET 2.0 Framework controls, and you leverage the same default binding property, that's all you need to do. Now I'll use an AddressBlock
example to show how you can change the default binding property.
Will My 1.1 Controls Work with Drag-Once Databinding?
Hmmmm, maybe. So far we've been able to tweak the control list easily because we're leveraging 2.0 controls. When we started down this path, we quickly realized we didn't have the right data about each control to determine which property to default Databind to. In typical Microsoft fashion, we had too much information. We thought about building a Google search into the designer to find the right databinding property. But then how would I build my demos on the plane just hours before the next conference?
The Devil Is in the Details
On the surface, you might think this is a relatively simple thing to do. Create a control, name it, create a label, and establish databinding. But wait. Which property should VS bind to? Many controls support databinding on multiple properties. Even the TextBox control supports databinding to Text and Tag properties. Look at Table 1 and you'll see that most controls have more then one bindable property.
Table 1: Controls and their bindable properties.
Checked, Tag, Text, Value
CheckAlign, Checked, CheckState, Tag, Text
SelectedItem, SelectedValue, Tag, Text
As you can imagine, this got even more complicated when we looked at complex controls such as the DataGridView. Sure we could assume DataSource
, but that's a very restrictive view for control vendors. Say it together, "I don't know what I don't know." Yes, we really do think about our third-party control vendors up front.
Now consider lookup controls such as the ListBox or the ComboBox, which actually databind in a two-dimensional fashion. For a ComboBox to work effectively, you need to establish two sets of properties. One set to populate the list, and one to pull out the selected value. I've illustrated this in Figure 4
Suppose you want an Order form. That form needs to display BillToState
and the ShipToState
fields. You may want to store the two-letter state code, but you want to display the full state name for your user. You can use a ComboBox to set several properties (see Table 2).
Table 2: ComboBox properties used for lookup.
The IList used to populate the combo box. This might be the States datatable from a DataSet or a List(Of States) object. Gotta love generics...
Indicates which property of the IList to use to display to the end user. DisplayMember could be the StateName column of the StatesDataTable or the Property name of the States object. We use Member because in this case we don't really need a property, just a named "member" of the collection.
Identifies which property of the IList to use to pass to the SelectedItem property. ValueMember could be the StateCode column of the StatesDataTable or the StateCode property of a States object.
The value of the property named in ValueMember from the list in DataSource, for the currently selected item.
I'll cover some cool new "lookup" control features in a future article. This is another one of my pet peeves, so look for some lookup features in a post-Beta 1 build of Visual Studio 2005.
So now that I've outlined the complexity, how did we solve this?