问题与网格数据绑定 [英] Issue with Grid data binding

查看:108
本文介绍了问题与网格数据绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的应用产生结果的一个具体结构的巨大的名单。问题是,如果我要显示它在DataGrid中,我要创建一个DataTable,并设置为将使用存储网格的数据源。所以,我创建了一个的BindingList类的我创建(称为 myRow ),并在myRow结构我有我需要为指向的值的属性的所有字段结果的实际列表。但问题是,用户可以添加结果自定义列清单;我不能改变的属性的 myRow 动态,我不希望使用一个DataTable(因为这将是我的实际结果的副本),如果我直接在DataGrid中创建自定义列设置其值细胞由细胞,在存储器中的栅格的尺寸变为非常高(我想这是因为设定值细胞由细胞导致细胞的特性要保存为每个小区,而不是一个较大的标准)。因此,没有人知道我怎么可以创建一个类行比使用属性为列不同的策略,这样我可以动态设置的列数在运行时?

Our application generate a huge list of result in a specific structure. The problem is that if I want to show it in a DataGrid, I have to create a DataTable and set it as the dataSource of the grid which will use memory. So I created a BindingList of a class that I created (called myRow) and in the structure of myRow I have all the fields that I require as properties pointing to the values in the actual list of results. But the problem is that users can add custom columns list of results; I can not change the properties of myRow dynamically, and I don't want to use a DataTable (because it will be a duplicate of my actual result) and if I create custom columns directly in the dataGrid and set their values cell-by-cell, the size of the grid in memory goes really high (I assume this is because setting values cell-by-cell causes the properties of cell to be saved for each cell instead of a bigger criteria). So does anyone know how can I create a class of row with a strategy different than using properties as columns, so that I can dynamically set the number of columns at runtime?

推荐答案

我认为这可以通过使用 TypeDescriptionProvider

i think this can be done by using a TypeDescriptionProvider.

<击>坏消息是:我从来没有这样做过,并不能提供太多的帮助

好消息是:我已经在这里找到一个例子:的DataGridView不显示对象它们实现ICustomTypeDescriptor

the GOOD news is: i've found an example here: DataGridView not showing properites of objects which implement ICustomTypeDescriptor

//修改

我使用的代码(见的性质在上面的链接)来构建一个例子,如何避免每个对象字典...

i used the code (see link above) to build an example how to avoid the dictionary per object ...

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, MyView, DataRow> rowSelector;
        Type type;
        public MyViewPropertyDescriptor(PropertyDescriptor descr, DataTable dt, Func<DataRow, object> getter, Action<DataRow, object> setter, Func<DataTable, MyView, DataRow> rowSelector, 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;
    }

}

和一个小例子,使得使用这...

and a little example that makes use of 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", dt, 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", dt, row => row["additionalData2"], (row, val) => row["additionalData2"] = val, (tab, v) => tab.Rows.OfType<DataRow>().First(x => x["id"].Equals(v.obj.id)), typeof(int));

        dataGridView1.DataSource = new BindingList<MyView>(data.Select(x => new MyView { obj = x }).ToList());
    }
}



当然,你将要提供更好的rowSelector或你想要一个Hashtable或任何数据结构替换数据表...只是一个例子。

of course you will want to provide a better rowSelector or replace the DataTable with a Hashtable or whatever datastructure you want ... just an example

这篇关于问题与网格数据绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆