Adam
Adam

Reputation: 2440

How to set Display member of combobox to a string nested within list of objects?

I should add that the objects are managed in a 3rd party .dll so I do not actually have the object definitions in my code.

I have a List<Foo> which I'm setting as the datasource for a ComboBox.

Assuming Foo object looks something like:

public class Foo
{
    Settings setting;
    public Foo(string title)
    {
        setting = new Settings();
        setting.Title = title;
    }
    //lots of other objects and values
}

public class Settings
{
    public Settings()
    {
    }
    public String Title {get; set;}
    //lot of other information
}

And my implementation here:

private void LoadList() //edited for SO testing sake, this is called in constructor
                        //of the form
{
    var foo = new List<Foo> {
        new Foo("MASTER 5DAY"),
        new Foo("5 Day Reminder"),
        new Foo("MASTER Welcome"),
        new Foo("Welcome Letter")
    };

    var master = foo.Where(x => x.Settings.Title.Contains("MASTER")).ToList();
    this.ddlMasterType = master; //This is the combobox

    //Now here I would want the display member of the ddl to be the title of each Foo object
    //But I need the value member to still contain all the other information of the Foo object
}

As listed in my implementation comments, I want to display the Foo.Settings.Title when I open the dropdown, but I still need the full object when I select it later.

Upvotes: 1

Views: 2663

Answers (3)

You're in a little bit of a pickle. If you set comboBox1.DataSource = foo;, ordinarily you'd set comboBox1.DisplayMember = "SomePropertyName"; and you'd be good. But in your case you need a path, not a name, and comboBox1.DisplayMember = "settings.Title"; will be ignored.

If you could alter Foo, you'd just add a readonly wrapper property to Foo:

public String Title { get { return settings.Title; } }

But you can't alter Foo.

So here's an option: Write a wrapper class that you can alter.

public class FooCarrier
{
    public Foo Foo { get; set; }
    public String Title { get { return Foo.settings.Title; } }
}

...

public Form1()
{
    InitializeComponent();

    comboBox1.DataSource = new List<Foo> {
        new Foo("MASTER 5DAY"),
        new Foo("5 Day Reminder"),
        new Foo("MASTER Welcome"),
        new Foo("Welcome Letter")
    }.Select(f => new FooCarrier { Foo = f }).ToList();

    comboBox1.DisplayMember = "Title";
    comboBox1.ValueMember = "Foo";

    comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;
}

private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    //  comboBox1.SelectedItem will be FooCarrier, but since we set 
    //  ValueMember to "Foo", SelectedValue is the Foo property of the selected
    //  item. 
    Foo selectedFoo = (Foo)comboBox1.SelectedValue;
}

You could also omit FooCarrier and use an anonymous type:

comboBox1.DataSource = new List<Foo> {
    new Foo("MASTER 5DAY"),
    new Foo("5 Day Reminder"),
    new Foo("MASTER Welcome"),
    new Foo("Welcome Letter")
}.Select(f => new { Foo = f, Title = f.Settings.Title }).ToList();

SelectedValue is still Foo, so you'll never need to cast to the actual item type.

Upvotes: 4

schwartzdotwork
schwartzdotwork

Reputation: 133

Try setting the displayMember to the Title Property:

  master.DataSource = fooList;
  master.DisplayMember = "Name"

Get the whole object by using:

  Foo foo = (Foo)master.SelectedItem;

or

  Foo foo = master.SelectedItem as Foo;

Upvotes: 0

pablocity
pablocity

Reputation: 504

You can set comboBox's data context as the whole list, and override ToString method of Foo class to show exactly what you want.

    public override string ToString()
    {
        return /*information you want to display, for example*/setting.Title;
    }

Upvotes: 0

Related Questions