假设我有一个WinForms DataGridView控件,我将数据绑定到自定义类型的IList,如下所示:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
var data = new ArrayList();
data.Add(new Person("Bob", 25));
data.Add(new Person("Alice", 23));
this.dataGridView1.DataSource = data;
}
这将显示列表名称为“名称”和“年龄”的列表项,从列表项的公共属性中巧妙地推断(通过反射)。 (根据我的测试,第一项。)
但如果我使用DataTable做同样的事情:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Row");
dt.Rows.Add("Bob", 25);
dt.Rows.Add("Alice", 23);
this.dataGridView1.DataSource = dt;
... DataGridView如何知道如何使用DataTable的列而不是公共属性? DataTable和DataRow似乎都没有实现提供此信息的任何接口。或者DataGridView是否了解DataTable类型,并以不同方式处理这种类型的数据源?
我问的原因是因为我想实现自己的“动态”数据源类型,而不依赖于固定属性。
答案 0 :(得分:3)
public class MyPropertyDescriptor<TComponent, TValue> : PropertyDescriptor
{
private readonly Func<TComponent, TValue> getter;
private readonly Action<TComponent, TValue> setter;
public MyPropertyDescriptor(string name, Func<TComponent, TValue> getter, Action<TComponent, TValue> setter)
: base(name, null)
{
this.getter = getter;
this.setter = setter;
}
public override bool CanResetValue(object component)
{
return true;
}
public override object GetValue(object component)
{
return getter((TComponent)component);
}
public override void ResetValue(object component)
{
setter((TComponent)component, default(TValue));
}
public override void SetValue(object component, object value)
{
setter((TComponent)component, (TValue)value);
}
public override bool ShouldSerializeValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return typeof(TComponent); }
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type PropertyType
{
get { return typeof(TValue); }
}
}
然后我修改了Person类以实现ICustomTypeDescriptor:
public class Person : ICustomTypeDescriptor
{
public string Name { get; set; }
public int Age { get; set; }
/* ... Unimplemented ICustomTypeDescriptor methods left out ... */
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[]
{
new MyPropertyDescriptor<Person, string>("My Name", p => p.Name, (p, s) => p.Name = s),
new MyPropertyDescriptor<Person, int>("My Age", p => p.Age, (p, i) => p.Age = i)
};
return new PropertyDescriptorCollection(propertyDescriptors);
}
}
现在GridView看起来像这样......
当然,这只是一个测试它有效的样本。在生产代码中,类型描述符可能不会映射到公共属性,尽管很高兴看到它们也可以用于自定义列显示名称(在类成员标识符中不允许使用空格和其他字符)。
答案 1 :(得分:2)
DataGridView的DataSource方法支持IListSource接口,例如DataTable和DataSet。
如果需要,此MSDN文章会提供更多信息。
答案 2 :(得分:1)
GridView1.DataSource = dt;
GridView1.DataBind();