如何解决网格数据绑定问题
| 我们的应用程序会在特定结构中生成大量结果。问题是,如果要在DataGrid中显示它,则必须创建一个DataTable并将其设置为将使用内存的网格的dataSource。因此,我创建了一个我创建的类的BindingList(称为myRow),在myRow的结构中,我拥有了所有需要的字段,这些字段作为属性指向实际结果列表中的值。但是问题在于用户可以添加自定义列结果列表;我无法动态更改myRow的属性,并且我不想使用DataTable(因为它将与我的实际结果重复),并且如果我直接在dataGrid中创建自定义列并逐个设置其值-cell,内存中网格的大小真的很高(我认为这是因为逐个单元设置值会导致为每个单元保存单元的属性,而不是更大的标准)。那么,有谁知道如何使用不同于将属性用作列的策略来创建行类,以便可以在运行时动态设置列数?解决方法
我认为这可以通过使用ѭ0来完成。
坏消息是:我以前从未做过,也无法提供太多帮助
好消息是:我在这里找到一个示例:DataGridView没有显示实现ICustomTypeDescriptor的对象的属性
//编辑
我使用代码(请参见上面的链接)构建了一个示例,该示例如何避免每个对象使用字典...
public class myRow
{
//your data storage class ...
public string txt { get; set; }
public int id { get; set; }
}
public class MyView:ICustomTypeDescriptor
{//your extendable view class ...
private static PropertyDescriptorCollection props = null;
static MyView()
{
TypeDescriptionProvider defaultProvider = TypeDescriptor.GetProvider(typeof(MyView));
props = new PropertyDescriptorCollection(defaultProvider.GetTypeDescriptor(typeof(MyView)).GetProperties().Cast<PropertyDescriptor>().ToArray(),true);
}
public static void addProperty(string name,DataTable dt,Func<DataRow,object> getter,Action<DataRow,object> setter,Func<DataTable,MyView,DataRow> rowSelector,Type PropType)
{
List<PropertyDescriptor> tmp;
if (props != null) tmp = props.Cast<PropertyDescriptor>().ToList();
else tmp = new List<PropertyDescriptor>();
PropertyDescriptor pd = TypeDescriptor.CreateProperty(typeof(MyView),name,PropType,null);
pd = new MyViewPropertyDescriptor(pd,dt,getter,setter,rowSelector,PropType);
tmp.Add(pd);
props = new PropertyDescriptorCollection(tmp.ToArray(),true);
}
//the data storage obj this view is referencing
public myRow obj;
public string TXT { // view-member known at compile time
get { return obj.txt; }
set { obj.txt = value; }
}
internal class MyViewPropertyDescriptor : PropertyDescriptor
{ // an example property descriptor that can link to data in a DataTable ...
DataTable dt;
Func<DataRow,object> getter;
Action<DataRow,object> setter;
Func<DataTable,DataRow> rowSelector;
Type type;
public MyViewPropertyDescriptor(PropertyDescriptor descr,Type PropType)
: base(descr)
{
this.dt = dt; // storage for additional data referenced by this property
this.getter = getter; //a getter that will take a DataRow,and extract the property value
this.setter = setter; //a setter that will take a DataRow and a value
this.rowSelector = rowSelector;//a row selector ... takes a dataset and the view object and has to return the assiciated datarow
this.type = PropType; // the type of this property
}
public override object GetValue(object component)
{
// using row selector and getter to return the current value ... you should add errorhandling here
return getter(rowSelector(dt,(MyView)component));
}
public override void SetValue(object component,object value)
{ // the setter ... needs errorhandling too
setter(rowSelector(dt,(MyView)component),value);
}
public override void ResetValue(object component)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override Type PropertyType
{
get { return type; }
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type ComponentType
{
get { return typeof(MyView); }
}
}
ICustomTypeDescriptor defaultDescriptor = TypeDescriptor.GetProvider(typeof(MyView)).GetTypeDescriptor(typeof(MyView));
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return defaultDescriptor.GetAttributes();
}
string ICustomTypeDescriptor.GetClassName()
{
return defaultDescriptor.GetClassName();
}
string ICustomTypeDescriptor.GetComponentName()
{
return defaultDescriptor.GetComponentName();
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return defaultDescriptor.GetConverter();
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return defaultDescriptor.GetDefaultEvent();
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return defaultDescriptor.GetDefaultProperty();
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return defaultDescriptor.GetEditor(editorBaseType);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return defaultDescriptor.GetEvents(attributes);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return defaultDescriptor.GetEvents();
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return props; // should really be filtered,but meh!
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return props;
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
}
还有一个利用这一点的小例子...
private void button1_Click(object sender,EventArgs e)
{
if (dataGridView1.DataSource == null)
{
List<myRow> data = new List<myRow>();
data.Add(new myRow { id = 1,txt = \"test 1\" });
data.Add(new myRow { id = 2,txt = \"test 2\" });
data.Add(new myRow { id = 3,txt = \"test 3\" });
DataTable dt = new DataTable();
dt.Columns.Add(\"id\",typeof(int));
dt.Columns.Add(\"additionalData1\",typeof(int));
dt.Columns.Add(\"additionalData2\",typeof(int));
Random rnd = new Random();
foreach (var item in data)
{
dt.Rows.Add(new object[] { item.id,rnd.Next(),rnd.Next() });
}
MyView.addProperty(\"additionalData1\",row => row[\"additionalData1\"],(row,val) => row[\"additionalData1\"] = val,(tab,v) => tab.Rows.OfType<DataRow>().First(x => x[\"id\"].Equals(v.obj.id)),typeof(int));
MyView.addProperty(\"additionalData2\",row => row[\"additionalData2\"],val) => row[\"additionalData2\"] = val,typeof(int));
dataGridView1.DataSource = new BindingList<MyView>(data.Select(x => new MyView { obj = x }).ToList());
}
}
当然,您将需要提供更好的rowSelector或将数据表替换为哈希表或所需的任何数据结构...仅是示例
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。