2009-05-19 120 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