Reputation: 26919
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
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
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
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
Reputation: 1
Better to use const string placed in the class Order and use those constants everywhere when binding datasource.
Upvotes: 0