5

When I set a DataSource on a control and want to use .ToString() as DisplayMember, I need to set the DisplayMember last or the ValueMember will override it.

MSDN on empty string as display member:

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.

Code to reproduce:

Class:

class SomeClass
{
    public string PartA { get; set; }
    public string PartB { get; set; }
    public string WrongPart { get { return "WRONG";  } }

    public override string ToString()
    {
        return $"{PartA} - {PartB}";
    }
}

Form:

var testObj = new SomeClass() { PartA = "A", PartB = "B" };
comboBox1.DataSource = new [] { testObj };
comboBox1.DisplayMember = "";
comboBox1.ValueMember = "WrongPart";

comboBox2.DataSource = new[] { testObj };
comboBox2.ValueMember = "WrongPart";
comboBox2.DisplayMember = "";

You can try it by making a new form and adding 2 combobox's.

Result:

enter image description here

Conclusion and question:

This can be easily fixed by setting them in the correct order however this is prone to errors, it also does not show this behavior if I use an actual property as DisplayMember instead of ""/ToString.

I would really like to know why it displays this behavior and if I could possibly set .ToString() explicitly as DisplayMember (for code clarity).

EpicKip
  • 4,015
  • 1
  • 20
  • 37
  • This seems like it's intended to show the value member if there is no display member set. From your code, I'd hazard a guess that this is triggered in the `ValueMember` set logic (something like `if(String.IsNullOrWhiteSpace(DisplayMember)) DisplayMember = value;` – Flater Sep 22 '17 at 12:40
  • @Flater Feasible answer, weird though if the documentation says you need an empty one for tostring (they should use value if its `null`) I will check in the referencesource, thanks for pointing me in the right direction! – EpicKip Sep 22 '17 at 12:41
  • @Flater Added a bit from the reference source, it does indeed do stuff if the setter of ValueMember if displaymember.Length == 0. – EpicKip Sep 22 '17 at 12:46
  • Checked out the method it goes to, this indeed changes the DisplayMember. I do think its strange behavior though :) – EpicKip Sep 22 '17 at 12:52
  • It's by design. If you take a look at [`ValueMember`](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ListControl.cs,3700b49cdaae76be) source code, you will see when `DisplayMember` is empty, it calls [`SetDataConnection`](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ListControl.cs,fefa2e9724563396) passing the `ValueMember` property info as `DisplayMember`. That's it. – Reza Aghaei Sep 22 '17 at 12:56
  • 1
    Rather than strange behavior, I think that it's an overly simple fix to achieve a default display value. They should've evaluated the value of `DisplayMember` at the time of **rendering** rather than at the time of **setting** `ValueMember`. Business logic in a setter is always a bad idea, and this is a perfect example of why it's a bad idea. – Flater Sep 22 '17 at 12:56
  • @Flater Mis-used the word strange, I thought strange in the sense of 'why'. And I totally agree, they should check the length/value when rendered instead of the string value name -_-. Thanks for taking the time! – EpicKip Sep 22 '17 at 12:58
  • @RezaAghaei I see it is by design now :) edited that in the bottom of the question. I do think its a bad choice in design. If I have time soon I will add the answer myself. Thanks for taking the time! – EpicKip Sep 22 '17 at 12:59
  • For a question having 4 upvotes, it's really better and less confusing to edit the question and remove the part that you answered the question, instead paste it in the answer. :) – Reza Aghaei Sep 22 '17 at 13:01
  • @RezaAghaei I thought it would be best to work the answer out a bit first, but I have seen you around and you know what you're talking about so good thinking, Ill put it in an answer – EpicKip Sep 22 '17 at 13:02
  • Great! it's much better now :) – Reza Aghaei Sep 22 '17 at 13:05
  • @RezaAghaei Thanks for the tip! – EpicKip Sep 22 '17 at 13:06

1 Answers1

2

I have searched in the reference source and found this bit:

if (!newValueMember.Equals(valueMember)) {
// If the displayMember is set to the EmptyString, then recreate the dataConnection
//
if (DisplayMember.Length == 0)
    SetDataConnection(DataSource, newValueMember, false);

SetDataConnection method signature:

private void SetDataConnection(object newDataSource, BindingMemberInfo newDisplayMember, bool force)

This sets a new DisplayMember

displayMember = newDisplayMember;

so now we've come to the root of the issue

EpicKip
  • 4,015
  • 1
  • 20
  • 37