我有一个winforms应用程序,它有一个DataGridView。我希望能够将此DataGridView的DataSource设置为任意IEnumerable,以便它显示该对象上的所有公共属性和字段。默认情况下,DataGridView仅显示属性
我确实知道如何重构类以将字段转换为属性,但我希望能够在不重构的情况下完成。有没有我可以在DataGridView上做的任何技巧,它会指示它显示字段,好像它们是属性?也许我可以使用一些库将数据源中的对象转换为包含字段的代理?
更新:感谢所有输入。自定义类型描述符可能是最通用的方法,因此我将其视为正确答案。出于我自己的目的,我决定采用另一种方式,将对象转换为DataTable,如下所示:
var dt = new DataTable();
foreach (var o in (IEnumerable)data)
{
var r = dt.NewRow();
foreach (var f in o.GetType().GetFields())
{
if (!dt.Columns.Contains(f.Name))
{
dt.Columns.Add(f.Name);
}
r[f.Name] = f.GetValue(o);
}
dt.Rows.Add(r);
}
dataGridView1.DataSource = dt;
答案 0 :(得分:1)
您可以尝试创建CustomTypeDescriptor
的子类,以覆盖GetProperties()
方法。然后你必须实现自己的TypeDescriptionProvider
类,将它们设置在所需类的TypeDescriptionProviderAttribute
中(将表示为行)。
示例:bind second-level properties
以下是我的例子:
<强> MyFieldsClass 强>
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
internal class MyFieldsClass
{
public int IntField;
public double DoubleField;
}
<强> FieldPropertyDescriptor 强>
internal sealed class FieldPropertyDescriptor<TComponent, TField> : PropertyDescriptor
{
private readonly FieldInfo fieldInfo;
public FieldPropertyDescriptor(string name)
: base(name, null)
{
fieldInfo = typeof(TComponent).GetField(Name);
}
public override bool IsReadOnly { get { return false; } }
public override void ResetValue(object component) { }
public override bool CanResetValue(object component) { return false; }
public override bool ShouldSerializeValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return typeof(TComponent); }
}
public override Type PropertyType
{
get { return typeof(TField); }
}
public override object GetValue(object component)
{
return fieldInfo.GetValue(component);
}
public override void SetValue(object component, object value)
{
fieldInfo.SetValue(component, value);
OnValueChanged(component, EventArgs.Empty);
}
}
<强> MyCustomTypeDescriptor 强>
internal sealed class MyCustomTypeDescriptor : CustomTypeDescriptor
{
public MyCustomTypeDescriptor(ICustomTypeDescriptor parent)
: base(parent)
{
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return GetProperties();
}
public override PropertyDescriptorCollection GetProperties()
{
return AddItems(base.GetProperties(),
new FieldPropertyDescriptor<MyFieldsClass, int>("IntField"),
new FieldPropertyDescriptor<MyFieldsClass, double>("DoubleField"));
}
private static PropertyDescriptorCollection AddItems(PropertyDescriptorCollection cols, params PropertyDescriptor[] items)
{
PropertyDescriptor[] array = new PropertyDescriptor[cols.Count + items.Length];
cols.CopyTo(array, 0);
for (int i = 0; i < items.Length; i++ )
array[cols.Count + i] = items[i];
PropertyDescriptorCollection newcols = new PropertyDescriptorCollection(array);
return newcols;
}
}
<强> MyTypeDescriptionProvider 强>
internal sealed class MyTypeDescriptionProvider : TypeDescriptionProvider
{
private ICustomTypeDescriptor td;
public MyTypeDescriptionProvider()
: this(TypeDescriptor.GetProvider(typeof(MyFieldsClass)))
{
}
public MyTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
return td ?? (td = new MyCustomTypeDescriptor(base.GetTypeDescriptor(objectType, instance)));
}
}
用法示例:
dataGridView1.DataSource = new List<MyFieldsClass>(new[] { new MyFieldsClass { IntField = 1, DoubleField = 10.0 } });