C#/ winforms:如何最好地绑定propertygrid和System.Data.DataRow

我有几个字段的System.Data.DataRows,其中大多数只是普通类型,如int,single,string。

使用propertygrid使它们可编辑的最佳方法是什么? 无论datarow有哪种字段,它都应该自动工作,但它不应该显示所有字段。 我想提供一个应该隐藏的属性列表。

由于DataTable是自动生成的,我无法添加自定义属性,如[可浏览(假)]

非常感谢!

编辑处理过滤; 很多tricker:除了获取DataRowView ,我们还需要提供一个自定义组件(通过pass-thru PropetyDescriptor )作为DataRowView (它本身假装是DataRow ) – 并过滤掉我们不PropetyDescriptor的属性不想要。

非常有趣的问题;-p在经典类中更容易解决,但下面适用于DataRow ;-p

请注意,您可以通过覆盖RowWrapperDescriptor其他成员,在此区域中执行其他操作以使某些属性不可编辑( IsReadOnly ),或具有不同的标题( DisplayName )或类别( Category )。

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Windows.Forms; static class program { [STAThread] static void Main() { DataTable table = new DataTable(); table.Columns.Add("ID", typeof(int)); table.Columns.Add("Foo", typeof(int)); table.Columns.Add("Bar", typeof(string)); table.Columns.Add("Audit", typeof(DateTime)); table.Rows.Add(1, 14, "abc", DateTime.MinValue); DataRow row = table.Rows.Add(2,13,"def", DateTime.MinValue); table.Rows.Add(3, 24, "ghi", DateTime.MinValue); RowWrapper wrapper = new RowWrapper(row); wrapper.Exclude.Add("ID"); wrapper.Exclude.Add("Bar"); Application.EnableVisualStyles(); Application.Run(new Form {Controls = { new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = wrapper}}}); } } [TypeConverter(typeof(RowWrapper.RowWrapperConverter))] class RowWrapper { private readonly List exclude = new List(); public List Exclude { get { return exclude; } } private readonly DataRowView rowView; public RowWrapper(DataRow row) { DataView view = new DataView(row.Table); foreach (DataRowView tmp in view) { if (tmp.Row == row) { rowView = tmp; break; } } } static DataRowView GetRowView(object component) { return ((RowWrapper)component).rowView; } class RowWrapperConverter : TypeConverter { public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } public override PropertyDescriptorCollection GetProperties( ITypeDescriptorContext context, object value, Attribute[] attributes) { RowWrapper rw = (RowWrapper)value; PropertyDescriptorCollection props = TypeDescriptor.GetProperties( GetRowView(value), attributes); List result = new List(props.Count); foreach (PropertyDescriptor prop in props) { if (rw.Exclude.Contains(prop.Name)) continue; result.Add(new RowWrapperDescriptor(prop)); } return new PropertyDescriptorCollection(result.ToArray()); } } class RowWrapperDescriptor : PropertyDescriptor { static Attribute[] GetAttribs(AttributeCollection value) { if (value == null) return null; Attribute[] result = new Attribute[value.Count]; value.CopyTo(result, 0); return result; } readonly PropertyDescriptor innerProp; public RowWrapperDescriptor(PropertyDescriptor innerProperty) : base( innerProperty.Name, GetAttribs(innerProperty.Attributes)) { this.innerProp = innerProperty; } public override bool ShouldSerializeValue(object component) { return innerProp.ShouldSerializeValue(GetRowView(component)); } public override void ResetValue(object component) { innerProp.ResetValue(GetRowView(component)); } public override bool CanResetValue(object component) { return innerProp.CanResetValue(GetRowView(component)); } public override void SetValue(object component, object value) { innerProp.SetValue(GetRowView(component), value); } public override object GetValue(object component) { return innerProp.GetValue(GetRowView(component)); } public override Type PropertyType { get { return innerProp.PropertyType; } } public override Type ComponentType { get { return typeof(RowWrapper); } } public override bool IsReadOnly { get { return innerProp.IsReadOnly; } } } }