Я играю с PropertyDescriptor и ICustomTypeDescriptor ( все еще ), пытаясь связать WPF DataGrid с объектом, для которого данные хранятся в словаре.
Поскольку, если вы передадите WPF DataGrid список объектов Dictionary, он автоматически сгенерирует столбцы на основе открытых свойств словаря (Comparer, Count, Keys and Values) моего словаря подклассов Person и реализует ICustomTypeDescriptor.
ICustomTypeDescriptor определяет метод GetProperties, который возвращает PropertyDescriptorCollection.
PropertyDescriptor является абстрактным, поэтому вы должны создать его подкласс, я подумал, что у меня будет конструктор, который принимает Func и параметры Action, которые делегируют получение и установку значений в словаре.
Затем я создаю PersonPropertyDescriptor для каждого ключа в словаре следующим образом:
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);
}
Проблема в том, что каждое свойство получает свои собственные Func и Action, но все они совместно используют внешнюю переменную s , поэтому, хотя DataGrid автоматически генерирует столбцы для "ID", "FirstName", "LastName", "Age "," Gender "они все получают и устанавливают против" Gender ", который является окончательным значением покоя s в цикле foreach.
Как я могу убедиться, что каждый делегат использует нужный словарный ключ, то есть значение s во время создания функции / действия?
Обязан.
Вот и остальная часть моей идеи, я просто экспериментирую здесь, это не «настоящие» классы ...
// 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);
}
}