I play with PropertyDescriptor and ICustomTypeDescriptor ( yet ), trying to associate a WPF DataGrid with an object for which data is stored in a dictionary.
Since if you pass a list of Dictionary objects to WPF DataGrid, it will automatically generate columns based on the public dictionary properties (Comparer, Count, Keys and Values) of the Person Person subclass and implements ICustomTypeDescriptor.
ICustomTypeDescriptor defines a GetProperties method that returns a PropertyDescriptorCollection.
The PropertyDescriptor property is abstract, so you have to subclass it, I decided that I will have a constructor that accepts Func and Action parameters that delegate the receipt and setting of values in the dictionary.
Then I create a PersonPropertyDescriptor for each key in the dictionary as follows:
foreach (string s in this.Keys) { var descriptor = new PersonPropertyDescriptor( s, new Func<object>(() => { return this[s]; }), new Action<object>(o => { this[s] = o; })); propList.Add(descriptor); }
The problem is that each property gets its own Func and Action, but they all share the external variable s , although the DataGrid automatically generates columns for "ID", "FirstName", "LastName", "Age", "Gender", all they get and set against "Paul", which is the final value of the rest s in the foreach loop.
How can I guarantee that each delegate uses the required dictionary key, i.e. s value during instance creation of Func / Action?
Significant duty.
Here is the rest of my idea, I'm just experimenting here, these are not “real” classes ...
// DataGrid binds to a People instance public class People : List<Person> { public People() { this.Add(new Person()); } } public class Person : Dictionary<string, object>, ICustomTypeDescriptor { private static PropertyDescriptorCollection descriptors; public Person() { this["ID"] = "201203"; this["FirstName"] = "Bud"; this["LastName"] = "Tree"; this["Age"] = 99; this["Gender"] = "M"; } //... other ICustomTypeDescriptor members... public PropertyDescriptorCollection GetProperties() { if (descriptors == null) { var propList = new List<PropertyDescriptor>(); foreach (string s in this.Keys) { var descriptor = new PersonPropertyDescriptor( s, new Func<object>(() => { return this[s]; }), new Action<object>(o => { this[s] = o; })); propList.Add(descriptor); } descriptors = new PropertyDescriptorCollection(propList.ToArray()); } return descriptors; } //... other other ICustomTypeDescriptor members... } public class PersonPropertyDescriptor : PropertyDescriptor { private Func<object> getFunc; private Action<object> setAction; public PersonPropertyDescriptor(string name, Func<object> getFunc, Action<object> setAction) : base(name, null) { this.getFunc = getFunc; this.setAction = setAction; } // other ... PropertyDescriptor members... public override object GetValue(object component) { return getFunc(); } public override void SetValue(object component, object value) { setAction(value); } }