Good call to Marty in the comments of my last post, who basically hit the nail on the head. I had been content to leave it alone and just go about setting them in that order, but something he said struck me as odd. He said (regarding setting the DisplayMember) “ which it is by default, but you also explicitly declared it that as well”. And that got me thinking about documented expected behavior, and actuality.
His contention is that basically when you Set ValueMember if DisplayMember is empty then replace with value member. Minus some syntactic sugar and refactoring, he’s right on target. I dug up the code in Reflector and found the story.
The problem is actually in the base System.Windows.Forms.ListControl and not the ComboBox which means that the behavior will probably manifest itself in the other data controls that inherit from ListControl.
Here’s the property set for DisplayMember:
public void set_DisplayMember(string value)
{
BindingMemberInfo info1 = this.displayMember;
try
{
this.SetDataConnection(this.dataSource, new BindingMemberInfo(value), false);
}
catch (Exception)
{
this.displayMember = info1;
}
}
And here’s the property set for ValueMember:
public void set_ValueMember(string value)
{
if (value == null)
{
value = "";
}
BindingMemberInfo info1 = new BindingMemberInfo(value);
if (!info1.Equals(this.valueMember))
{
if (this.DisplayMember.Length == 0)
{
this.SetDataConnection(this.DataSource, info1, false);
}
if (((this.dataManager != null) && !"".Equals(value)) && !this.BindingMemberInfoInDataManager(info1))
{
throw new ArgumentException(SR.GetString("ListControlWrongValueMember"), "value");
}
this.valueMember = info1;
this.OnValueMemberChanged(EventArgs.Empty);
this.OnSelectedValueChanged(EventArgs.Empty);
}
}
So, basically, there it is. If DisplayMember.Length == 0 then we’re going to SetDataConnection (which sets the DisplayMember to whatever is passed in…in this case BindingMemberInfo(value) so in essence the ValueMember). So by calling set valuemember last…we effectively reset our displaymember. And that would seem to make sense as a fail-safe if you’re coding it, and I can see why it happened, but the problem is that the Expected API behavior is that using an empty string on DisplayMember should result in the ToString() method of the bound object (not the ValueMember) being called. That is not the result of this code though. And to double-check, (going back to what Marty said that led me to look further), I didn’t explicitly set my DataMembers at all, and got the same thing, the ValueMember as the DisplayMember.
Quoting the documentation for this property:
The controls that inherit from ListControl can display diverse types of objects. If the specified property does not exist on the object or the value of DisplayMember is an empty string (""), the results of the object's ToString method are displayed instead.
Where I come from, this counts as a bug (a minor one to be sure). Don’t document a behavior if it doesn’t really work that way.
So all this is just an exercise in finding out why you have to do a workaround, it doesn’t really mean much, and it’s not breaking an otherwise great framework (.net ftw!), but it was kind of fun to check out and see that hey, even the big boys make dumbass mistakes too!
Tags:
Code UI dotnet