2009-05-19 84 views
26

我有一组“动态数据”,我需要绑定到GridControl。直到现在,我一直在使用属于System.Data命名空间一部分的标准DataTable类。这工作得很好,但我被告知我不能使用它,因为它对于跨客户端的服务器之间的网络进行序列化太重了。数据绑定动态数据

所以我想我可以轻松地复制DataTable类的'精简'版本,只需要一个类型为List<Dictionary<string, object>>的List,其中List代表行的集合,每个Dictionary代表一行,列名和值作为KeyValuePair类型。我可以设置网格有列数据字段属性,就像

我是做了DataTable的列名。做

gridControl.DataSource = table; 
gridControl.RefreshDataSource(); 

网格有后,但是以匹配键在Dictionary(没有数据...

我想我需要实现IEnumerator - 任何帮助,将不胜感激

实例调用代码看起来是这样的:

var table = new List<Dictionary<string,object>>(); 

var row = new Dictionary<string, object> 
{ 
    {"Field1", "Data1"}, 
    {"Field2", "Data2"}, 
    {"Field3", "Data3"} 
}; 

table.Add(row); 

gridControl1.DataSource = table; 
gridControl1.RefreshDataSource(); 
+0

GridControl?你的意思是DataGridView? – 2009-05-19 11:44:21

回答

61

欢迎来到System.ComponentModel的精彩世界。 .NET的这个黑暗角落非常强大,但非常复杂。

一句小心;除非你有足够的时间来做这件事 - 你可以简单地用你喜欢的任何机制序列化它,但是在每一个末端将它重新水化成一个DataTable ......接下来的不是那些胆小的人; p

首先 - 数据绑定(对于表)的作品对名单IList/IListSource) - 所以List<T>应该罚款(编辑:我误解的东西)。但它不会理解你的字典实际上是列...

要获得一个类型假装有列,你需要使用自定义PropertyDescriptor实现。有几种方法可以做到这一点,具体取决于列定义是否始终相同(但是在运行时(即可能来自配置)),或者它是否随每次使用情况而改变(如每个实例如何可以有不同的列)。

对于“每个实例”的定制,你需要看看ITypedList - 此兽(在除了IList实现)有呈现表格数据属性的好玩的事......但它并不孤单:

对于“按类型”的定制,你可以看看TypeDescriptionProvider - 这可以为一类建议动态属性...

...或者你可以实现ICustomTypeDescriptor - 但这只是使用(名单)在非常偶尔情况下(对象索引器()“),并且在绑定点处列表中至少有一行)。 (当绑定离散对象时,这个接口更有用 - 即不是列表)。

实施ITypedList,并提供PropertyDescriptor模型是艰苦的工作...因此它只是偶尔做。我对它很熟悉,但我不会为了笑而去做。


这里有一个非常,非常简化的实现(所有列都是字符串,没有通知(通过描述符),无验证(IDataErrorInfo),无转换(TypeConverter),不需要额外的列表支持(IBindingList/IBindingListView) ,没有抽象(IListSource),没有其他的元数据/属性等):

using System.ComponentModel; 
using System.Collections.Generic; 
using System; 
using System.Windows.Forms; 

static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     PropertyBagList list = new PropertyBagList(); 
     list.Columns.Add("Foo"); 
     list.Columns.Add("Bar"); 
     list.Add("abc", "def"); 
     list.Add("ghi", "jkl"); 
     list.Add("mno", "pqr"); 

     Application.Run(new Form { 
      Controls = { 
       new DataGridView { 
        Dock = DockStyle.Fill, 
        DataSource = list 
       } 
      } 
     }); 
    } 
} 
class PropertyBagList : List<PropertyBag>, ITypedList 
{ 
    public PropertyBag Add(params string[] args) 
    { 
     if (args == null) throw new ArgumentNullException("args"); 
     if (args.Length != Columns.Count) throw new ArgumentException("args"); 
     PropertyBag bag = new PropertyBag(); 
     for (int i = 0; i < args.Length; i++) 
     { 
      bag[Columns[i]] = args[i]; 
     } 
     Add(bag); 
     return bag; 
    } 
    public PropertyBagList() { Columns = new List<string>(); } 
    public List<string> Columns { get; private set; } 

    PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) 
    { 
     if(listAccessors == null || listAccessors.Length == 0) 
     { 
      PropertyDescriptor[] props = new PropertyDescriptor[Columns.Count]; 
      for(int i = 0 ; i < props.Length ; i++) 
      { 
       props[i] = new PropertyBagPropertyDescriptor(Columns[i]); 
      } 
      return new PropertyDescriptorCollection(props, true);    
     } 
     throw new NotImplementedException("Relations not implemented"); 
    } 

    string ITypedList.GetListName(PropertyDescriptor[] listAccessors) 
    { 
     return "Foo"; 
    } 
} 
class PropertyBagPropertyDescriptor : PropertyDescriptor 
{ 
    public PropertyBagPropertyDescriptor(string name) : base(name, null) { } 
    public override object GetValue(object component) 
    { 
     return ((PropertyBag)component)[Name]; 
    } 
    public override void SetValue(object component, object value) 
    { 
     ((PropertyBag)component)[Name] = (string)value; 
    } 
    public override void ResetValue(object component) 
    { 
     ((PropertyBag)component)[Name] = null; 
    } 
    public override bool CanResetValue(object component) 
    { 
     return true; 
    } 
    public override bool ShouldSerializeValue(object component) 
    { 
     return ((PropertyBag)component)[Name] != null; 
    } 
    public override Type PropertyType 
    { 
     get { return typeof(string); } 
    } 
    public override bool IsReadOnly 
    { 
     get { return false; } 
    } 
    public override Type ComponentType 
    { 
     get { return typeof(PropertyBag); } 
    } 
} 
class PropertyBag 
{ 
    private readonly Dictionary<string, string> values 
     = new Dictionary<string, string>(); 
    public string this[string key] 
    { 
     get 
     { 
      string value; 
      values.TryGetValue(key, out value); 
      return value; 
     } 
     set 
     { 
      if (value == null) values.Remove(key); 
      else values[key] = value; 
     } 
    } 
} 
+0

真棒回答我会给它一个让你知道我如何得到... – 2009-05-19 12:51:12