我发现 Bernardo 的 DeepBindingList 可以挽救生命,现在我想通过指出代码存在循环问题来回馈一些东西。意思是,如果 T 有一个 T 类型的成员,或者它本身有一个 T 类型的成员,那么 GetItemProperties() 中的递归将导致堆栈爆炸。
有不同的方法来处理这样的问题,但我实施的方法利用了这样一个事实,即我总是提前知道哪些属性将用作我的网格的列。因此,我创建了一个方法来获取这些列的属性:
private PropertyDescriptorCollection propertyDescriptors;
public void SetItemProperties(IList<string> names)
{
var list = new List<PropertyDescriptor>();
foreach (var name in names)
AddProperty(name, list);
propertyDescriptors = new PropertyDescriptorCollection(list.ToArray());
}
private void AddProperty(string name, List<PropertyDescriptor> list)
{
Type propType = typeof (T);
PropertyDescriptor parent = null;
foreach (var part in name.Split('.'))
{
PropertyDescriptor prop = TypeDescriptor.GetProperties(propType).Cast<PropertyDescriptor>().FirstOrDefault(pd => pd.Name == part);
if (prop == null)
return;
list.Add(new DeepPropertyDescriptor(prop, parent));
propType = prop.PropertyType;
parent = prop;
}
}
(我没有费心避免重复的 PropertyDescriptors,当两个或多个“孙子”共享同一个父级时,可能会出现重复的 PropertyDescriptors,如 Tab 和 Tac 他们没有给我带来任何麻烦,所以我把它留给下一个人修复。)
我在GetItemProperties()的开头添加了一个测试,所以:
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
if (propertyDescriptors != null)
return propertyDescriptors;
这样,如果我已经调用了 SetItemProperties(),它什么也不做。
我也发现接受列表参数的构造函数限制太多,所以我替换了
public DeepBindingList(IList<T> list)
: base(list)
{
}
与
public DeepBindingList(IEnumerable<T> list)
{
foreach (var t in list)
{
Add(t);
}
}
我希望有人觉得这很有用。