Using Auto-Populated Combo Boxes With Non-Unique Display Members
Overview
Data-bound Combo Boxes have a Value Member and a Display Member. The Value Member must be unique and is typically associated with a database primary key. Often the Display Member and Value Member fields are the same. This is what is displayed in column 1 and column 2 displays a description related to the Value/Display Member. On other occasions the Value member itself may not be displayed (because it is some kind of 'code') and the Display Member provides a more friendly indication of which Value row has been selected by the user.
Almost all of the OP 'Auto-Populated' Combo Boxes consist of a Display Member in column 1 that is unique, but there is no intrinsic reason for this to be the case. On very rare occasions we can encounter the situation where some of our unique Value Members share a common Display Member value. An example of this is the Combo Box that displays International Dialling Code (IDC) prefixes. So, for example, both Canada and the United States have a prefix of +1. OP stores the country code for the phone number in the database - for the very good reason that countries have IDC prefixes and countries can decide to change their prefix as the number of consumers grows and limits are reached on subscribers. One day Canada may decide that it needs its own prefix. If all our Partners contained the IDC in the database it would be a difficult undertaking to work out whether each partner with a +1 code should be changed to use the new code, whereas by storing a partner's telephone country it is just a change in one place to change the prefix for every Canadian partner at once.
This is why the IDC prefix is a good example of a Combo Box that can have two rows in the Combo list with +1 (Display Member). One row for a Value Member of CA and the other for a Value Member of US. The Combo Box list shows both the +1 and the country code and the full country name when dropped down and the country name in the attached label when closed up.
We expected this to be no problem for .NET to handle. But the bad news (at least as far as Windows is concerned) is that the Windows API always uses the first occurrence of the Display Member to determine which is the selected Value Member!
The consequence of this is
- When a screen loads Windows initially selects the wrong item in the Combo Box. (In our example, if the US is the database country, the Combo Box will initially display +1 and Canada).
- When you set the selected country to +1 US the data will be saved as a country code (Value Member value) of Canada
- When your selected country is +1 US and you open the drop down list the selected item will be +1 Canada
There is plenty on the internet about this problem but there were no solutions. However we worked on it for OP and our code has been written so that we can cope with non-unique Display Members provided the developer writes a small piece of manual code to define at least one extra column in the underlying database table.
The way we solved the third (and most difficult) of the three problems above was to interrupt the action of displaying the list and re-order the list so that the true selected country is placed first in its small group of non-unique Display Members. This is slightly unusual, but the big advantage which outweighs the unconventional behaviour is that Windows will place the selected item at the top of the list. This means that the duplicate items are all always visible, which would not be the case if the 'original' order were maintained because sometimes the alternative country would be hidden 'off the top'.
The code implementation for a non-unique Display Member is written in TCmbAutoPopulated in a method named 'CreateNonUniqueDataTable'. This method takes two parameters:
- a DataTable object that has already been fully populated with the DataRows of data to be displayed.
- a table name
It is the developer's responsibility to write the few lines of code in this method that will set up a new column in the table and initialise the values for it. The existing code for setting up the International Dialling Code prefix can be used as an example. You will be adding a column with the name defined in the system constant 'NonUniqueSortMember'. Then you will set initial values for this column in all the rows of the table. The actual values have no intrinsic relationship to the data - they are a sort order and relate only to the relative position or ranking of items that have the same Display Member value. So the simplest initialisation is to set each value to the rowID.
The action of adding code to this method is all that is needed to mark this particular combo box as containing non-unique items.
By the way, it is worth mentioning that this whole 'problem' does not apply if the drop-down style of the Combo Box is set to 'DropDownList' - but that removes the ability to type the value of the IDC direct into the text area. That was not an acceptable option for us.
Optional Configuration
See Options for Combo Boxes with Non-Unique Display Members.