Bohn
Bohn

Reputation: 26919

Assign Class properties at run time

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?

Upvotes: 1

Views: 218

Answers (4)

prashanth
prashanth

Reputation: 2099

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>();

Upvotes: 3

Jesse C. Slicer
Jesse C. Slicer

Reputation: 20157

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);
    }
}

Upvotes: 2

itsmatt
itsmatt

Reputation: 31416

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.

Upvotes: 2

Roman
Roman

Reputation: 1

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

Upvotes: 0

Related Questions