void Bind(ListControl control, IEnumerable<Entity> entities, string displayMember)
{
control.DataSource = entities.ToArray();
control.ValueMember = "ID";
control.DisplayMember = displayMember;
}
I've got an Entity with an ID and various subclasses of this. The above method would perhaps live in a presenter (base) class.
When I run a form that calls this with "Name" as DisplayMember, something very odd happens: The list control (a ComboBox in my test, but these properties are inherited from ListControl) displays the entity ID rather than its Name.
I attached the debugger and stepped into the method. The parameter "displayMember" is correct ("Name") and no exceptions occur, but the DisplayMember property becomes "ID" when ValueMember is set (along with ValueMember itself) and then seemingly just ignores any calls to the setter, neither throwing an exception nor actually changing the property value.
If I don't invoke ToArray() and bind directly to the given enumerable it displays the name, but then I end up potentially binding two or more lists to the same data source, which causes other strange effects. For one thing it becomes impossible to select items independently in the lists linked to the same datasource. I've no idea why this is, but ToArray() overcomes this by making a shallow copy.
I've also tried to fill lists by directly modifying the Items collection:
void Fill(ComboBox combo, IEnumerable<Entity> entities, string displayMember)
{
combo.DataSource = null;
combo.Items.Clear();
combo.DisplayMember = displayMember;
combo.ValueMember = "ID";
foreach (var e in entities)
combo.Items.Add(e);
}
Note that I can't use ListControl here, because it doesn't have the Items collection. Still, it's a possible workaround worth exploring, so I did.
This at first looked like it worked - it displays the name as it should. But again other, new problems soon crop up. In this case it's the SelectedValue property that just stops working, so I cannot do this:
void Select(ListControl list, int entityID)
{
list.SelectedValue = entityID;
}
void Select(ListControl list, Entity item)
{
Select(list, item.ID);
}
I want to be able to use the same object instance that is loaded in the list itself, another instance representing the same entity, or just the ID value itself. In many cases the lists will contain cached data while the selected item will reflect a property value of some other entity. Say Transaction.CurrencyID or Transaction.Currency.
It's difficult to believe Microsoft's intention was to make it so that SelectedValue should only work when you have a DataSource, and DisplayMember should only work when you don't. Presumably it is this brand-new approach in the latest framework versions where exceptions are NOT thrown even when things fail that make it impossible for me to have any idea what I'm doing wrong...
How do I solve this?