Sometimes you want to manipulate the order in which properties are used for databinding. Eg: If you drag and drop an object datasource on a DataGridView you have no control in which order it binds the properties. Offcourse, you can order the columns by moving them around… Today someone asked the following:
I would like to have it come from the class in the order I want it. Any suggestions on how to set the display order without referencing the actual member names?
I started with the implementation of a PropertyOrderAttribute:
[AttributeUsage(AttributeTargets.Property)]
public class PropertyOrderAttribute : Attribute
{
private int order;
public PropertyOrderAttribute(int order)
{
this.order = order;
}
public int Order
{
get { return this.order; }
}
}
So the user can use this attribute to define the order in which the properties should appear as following:
class Foo
{
private int id;
private string name;
private DateTime birthDay;
public Foo(int id, string name, DateTime birthDay)
{
this.id = id;
this.name = name;
this.birthDay = birthDay;
}
[PropertyOrder(0)]
public int Id
{
get { return id; }
set { id = value; }
}
[PropertyOrder(2)]
public string Name
{
get { return name; }
set { name = value; }
}
[PropertyOrder(1)]
public DateTime BirthDay
{
get { return birthDay; }
set { birthDay = value; }
}
}
And now i implement a generic BindingList that makes use of the PropertyOrderAttributes:
class PropertyOrderBindingList<t> : BindingList<t>, ITypedList
{
public PropertyOrderBindingList()
: base()
{
//
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
PropertyDescriptorCollection typePropertiesCollection = TypeDescriptor.GetProperties(typeof(T));
return typePropertiesCollection.Sort(new PropertyDescriptorComparer());
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
return string.Format("A list with Properties for {0}", typeof(T).Name);
}
}
class PropertyDescriptorComparer : IComparer
{
public int Compare(object x, object y)
{
if (x == y) return 0;
if (x == null) return 1;
if (y == null) return -1;
PropertyDescriptor propertyDescriptorX = x as PropertyDescriptor;
PropertyDescriptor propertyDescriptorY = y as PropertyDescriptor;
PropertyOrderAttribute propertyOrderAttributeX = propertyDescriptorX.Attributes[typeof(PropertyOrderAttribute)] as PropertyOrderAttribute;
PropertyOrderAttribute propertyOrderAttributeY = propertyDescriptorY.Attributes[typeof(PropertyOrderAttribute)] as PropertyOrderAttribute;
if (propertyOrderAttributeX == propertyOrderAttributeY) return 0;
if (propertyOrderAttributeX == null) return 1;
if (propertyOrderAttributeY == null) return -1;
return propertyOrderAttributeX.Order.CompareTo(propertyOrderAttributeY.Order);
}
}
With all this infrastructure it becomes as easy as:
public Form1()
{
InitializeComponent();
PropertyOrderBindingList<foo> fooList = new PropertyOrderBindingList<foo>();
fooList.Add(new Foo(1, "Timvw", new DateTime(1980, 4, 30)));
fooList.Add(new Foo(2, "Mike", new DateTime(1984, 1, 1)));
this.dataGridView1.DataSource = fooList;
}
Hey Tim. You were helping me in the MSDN forum with this exact issue. My needs are just a bit different.
I want to be able to set the display order of the properties dynamicaly. I would like to be able to pass in the order
to the BindingList so that I can make a call to get that List, each having a unique order of my choosing at that momemt.
does that make sense? Thanks for your help, Ive learned a lot, and this is something I am just flat out stuck on.
Hello, i’ve added an example of a DictionaryPropertyDescriptorComparer to the PropertyOrder.zip code. In the demo application you can choose the order of the Attributes and as soon as you hit the Show button the columns will appear in the wanted order… (The problem with this implementation is that you end up with pairs of (string PropertyName, int displayIndex) in the implementation. If i understood well that’s exactly what you were trying to avoid from the beginning)
I think this is going to work great. Now I can have the DAL get the BindingList in the order I want, being as I dont mind the DAL actually “knowing” the fild names, I can send this to the screen and it will have no idea the field names, just the order. Thanks so much.
Sweat ass article …
This worked great for what I needed to do.
Thanks a lot!!!
Great article
Thanks for you support.
Hi,
i tried your PropertyOrderBindingList, but it dont works with multi-Level data in an infragistics ultrawingrid. i have a propertyorderbindinglist of a custom type and in this type i have a property with another propertyorderbindinglist of another custom type. the ultragrid shows in the second hierarchy exactly the same columns as in the first (which is wrong), but without values. and then it shows a + for a third hierarchy (that does not exists in the data), and when i open this, i get a red cross. the ultragrid crashes. if i change both lists to normal bindinglists instead of propertyorderbindinglist it all work fine like expected. but then the propertyorder-feature is lost
Can you help me ?
thanks,
Uwe
It’s a nice article. This is eactly I am looking out for. Thanks,
hello,
I copied the PropertyOrderAttribute class in my project, and then I tried giving id to my customer class properties, but whenever I instantiate the class it never provide the properties in the given index order.
e.g.
[propertyorder(1)]
public string Name
get{}
set{}
[propertyorder(0)]
public string RollNo
get{}
set{}
Customer obj =new customer();
obj.Name; it shows the name most upper in the list of properties But I want RollNo to be upper than Name;