.NET DataGridView显示对象字段

时间:2014-02-27 18:59:46

标签: c# .net winforms datagridview

我有一个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;

1 个答案:

答案 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 } });