1

Let's say I have an Order class that has properties such as OrderName, OrderNum , etc...

then to populate a ComboBox with a list of items from this class, let's say I do it like this:

comboBox1.DisplayMember = "OrderName";
comboBox1.ValueMember = "OrderNum";
comboBox1.DataSource = list.ToArray<Order>();

So here I am hard coding the name of those fields in the code such as "OrderName". Is there a better way of doing this rather than hard coding the name of the fields? Does it need some sort of dependency injection tricks? What do you suggest?

Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
Bohn
  • 26,091
  • 61
  • 167
  • 254
  • You could make the strings constants... – Lews Therin Sep 25 '12 at 16:45
  • nop! I mean what if the name of the properties on the class changes later...then again I have to go to code and change these two..either here or well in the constants. – Bohn Sep 25 '12 at 16:47

4 Answers4

3

If possible, you can proceed as @JesseCSlicer has mentioned, but if you can't change your business classes, then you can take this approach:

Based on this SO answer, we can write our own helper:

public static class PropHelper<T>
{
    public static string PropName<R>(Expression<Func<T,R>> exp)
    {
        var mem = exp.Body as MemberExpression;
        if(mem != null) return mem.Member.Name;     
        throw new ArgumentException("Invlaid Property Name");
    }
}

And use it:

comboBox1.DisplayMember = PropHelper<Order>.PropName(o => o.OrderName);
comboBox1.ValueMember = PropHelper<Order>.PropName(o => o.OrderNum);
comboBox1.DataSource = list.ToArray<Order>();
Community
  • 1
  • 1
prashanth
  • 2,059
  • 12
  • 13
  • nice! what is the job of PropHelper? it returns property names of a class? What is a good description for what this class does? Thanks – Bohn Sep 25 '12 at 17:42
2

Below is a modified class I use in several of my ASP.NET applications. The way I'd assign it in your sample is like this:

var orders = model.GetOrders(...);

comboBox1.DisplayMember = OrderQueryResults.DisplayMember;
comboBox1.ValueMember = OrderQueryResults.ValueMember;
comboBox1.DataSource = orders.Results;

Class:

public sealed class OrderQueryResults : IOrderQueryResults
{
    private const string DisplayName = "OrderName";

    private const string ValueName = "OrderNum";

    private readonly IEnumerable<IOrderQueryResult> results;

    private readonly object extra;

    private OrderQueryResults(IEnumerable<IOrderQueryResult> results, object extra)
    {
        this.results = results;
        this.extra = extra;
    }

    public string DisplayMember
    {
        get
        {
            return DisplayName;
        }
    }

    public string ValueMember
    {
        get
        {
            return ValueName;
        }
    }

    public IEnumerable<IOrderQueryResult> Results
    {
        get
        {
            return this.results;
        }
    }

    public object Extra
    {
        get
        {
            return this.extra;
        }
    }

    public static IOrderQueryResults Create(IEnumerable<IOrderQueryResult> results, object extra)
    {
        if (results == null)
        {
            throw new ArgumentNullException("results");
        }

        return new OrderQueryResults(results.ToList(), extra);
    }
}
Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
2

Those are just properties of the Order, right? So you could use const - and that would be much better than literals in the code - but you can certainly change them at run time if you wish. You just need to know what they are.

In your class "OrderName" and "OrderNum" are just strings which represent the names of the properties, so if you happened to have other properties in your Order class, you could get the names of those properties and assign them, say, from some user action.

If you wanted to, you could use reflection to examine the Order class. Something like:

Type theType =(typeof(Order));
// Get the public properties.
PropertyInfo[] thePropertyInfo =
    theType.GetProperties(BindingFlags.Public|BindingFlags.Instance);

To get the name of any particular property in that PropertyInfo array you could something like:

thePropertyInfo[i].Name;

would give you the name of the ith property in the object.

So, you could then, say, put those properties into some list that is, itself bound to a control - like a ComboBox and then pick at run time what DisplayMember and ValueMember would be used, then just set those and the binding will automatically update.

itsmatt
  • 31,265
  • 10
  • 100
  • 164
  • 1
    What would be really cool is if the `ComboBox` itself would query the object in its `DataSource` just like this (using a convention of what the properties would be named for display and value) when its own `DisplayMember` and `ValueMember` properties are left blank. – Jesse C. Slicer Sep 25 '12 at 17:01
  • thanks, sorry I don't understand this part very well: "would give you the name of the ith property in the object. So, you could then, say, put those properties into some list that is, itself bound to a control - like a ComboBox and then pick at run time what DisplayMember and ValueMember would be used, then just set those and the binding will automatically update." – Bohn Sep 25 '12 at 17:09
  • 1
    So, what I mean by that @BDotA is that once you've retrieved the `PropertyInfo` objects in that array, you've got that names of all the properties, you can use those to update the `DisplayMember` and/or `ValueMember` just by setting those properties to the `.Name` property of the given `PropertyInfo` object in the array. Just like if you'd changed it with literals from "PropertyA" to "PropertyB", it'll update the binding for you. – itsmatt Sep 25 '12 at 17:20
  • correct, but the array is index by integers so how can I know what index is used for what field? so I can assign the correct field – Bohn Sep 25 '12 at 17:23
  • 1
    Can you rephrase your question? I'm not sure I follow. If you've got an enumerable (like this array) and you're going to pick from that enumerable somehow (e.g., you've stuck them to a control and the user picks the string from a dropdown), then you don't really care where they are in the array. Instead you care about the `.Name` property of the one you picked. Someone or something has to pick the appropriate property from that enumerable to get the `.Name` string. The array index probably isn't that important. – itsmatt Sep 25 '12 at 17:34
  • oh I see, sorry for confusion. Those Property names are not being binded to anythig, so there won't be like a combobbx that I can say Ok pick this PropertyName for DisplayName...now this time pick this other property name for DisplayName....they are always the ones I have hard coded, But My question was about to oh well what if later someone changes the names of those fields in business object so then my hard coded won't work because the name has changed. – Bohn Sep 25 '12 at 17:47
0

Better to use const string placed in the class Order and use those constants everywhere when binding datasource.

Roman
  • 1
  • 1
  • I mean what if the name of the properties on the class changes later...then again I have to go to code and change these two..either here or well in the constants. – Bohn Sep 25 '12 at 16:55
  • How would this be any better than the alternative? – Jesse Sep 26 '12 at 02:20