2009-05-19 50 views
26

Tôi có một tập hợp 'dữ liệu động' mà tôi cần phải liên kết với GridControl. Cho đến bây giờ, tôi đã sử dụng lớp DataTable chuẩn là một phần của không gian tên System.Data. Điều này đã làm việc tốt, nhưng tôi đã nói với tôi không thể sử dụng này vì nó quá nặng cho serialization trên mạng giữa máy chủ của khách hàng &. Vì vậy, tôi nghĩ rằng tôi có thể dễ dàng tái tạo phiên bản 'cắt giảm' của lớp DataTable bằng cách chỉ cần có một loại List<Dictionary<string, object>> theo đó Danh sách thể hiện tập hợp các hàng và mỗi Từ điển đại diện cho một hàng có tên cột và giá trị như một loại KeyValuePair. Tôi có thể thiết lập các Lưới có các thuộc tính cột DataField để phù hợp với những người trong những chìa khóa trong từ điển (giống như tôi đã làm cho tên cột của DataTable.Dữ liệu động liên kết dữ liệu

Tuy nhiên sau khi làm

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

Lưới điện có không có dữ liệu ...

tôi nghĩ tôi cần phải thực hiện IEnumerator - bất kỳ sự giúp đỡ về vấn đề này sẽ được nhiều đánh giá cao

Ví dụ mã gọi trông như thế này:

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? Bạn có nghĩa là DataGridView? –

Trả lời

61

Chào mừng bạn đến với thế giới tuyệt vời của System.ComponentModel. Góc tối của .NET rất mạnh, nhưng rất phức tạp.

Một lời cảnh cáo; trừ khi bạn có rất nhiều thời gian cho việc này - bạn có thể làm tốt để đơn giản hóa nó trong bất kỳ cơ chế nào bạn hài lòng, nhưng bù lại nó trở lại thành một DataTable ở mỗi đầu ... những gì sau đây không dành cho những người yếu tim; p

thứ nhất - dữ liệu ràng buộc (đối với bảng) hoạt động chống lại danh sách (IList/IListSource) - vì vậy List<T> nên được tốt (chỉnh sửa: tôi không nhận định một cái gì đó). Nhưng nó sẽ không hiểu rằng từ điển của bạn thực sự là cột ...

Để có loại giả vờ có cột bạn cần sử dụng triển khai PropertyDescriptor tùy chỉnh. Có một số cách để làm điều này, tùy thuộc vào việc định nghĩa cột luôn giống nhau (nhưng được xác định trong thời gian chạy, tức là có thể từ cấu hình) hoặc liệu nó có thay đổi theo cách sử dụng hay không (như cách mỗi trường hợp DataTable có thể có các cột khác nhau).

Đối với "mỗi trường hợp" tùy biến, bạn cần phải nhìn vào ITypedList - con quái vật này (thực hiện trong Ngoài-IList) có nhiệm vụ vui vẻ trình bày thuộc tính cho dữ liệu bảng ... nhưng nó không phải là một mình:

đối với "mỗi kiểu" tùy biến, bạn có thể nhìn vào TypeDescriptionProvider - điều này có thể gợi ý tính năng động cho một lớp học ...

... hoặc bạn có thể thực hiện ICustomTypeDescriptor - nhưng điều này chỉ được sử dụng (đối với danh sách) trong rất trường hợp không thường xuyên (một đối tượng lập chỉ mục ()") và ít nhất một hàng trong danh sách tại điểm ràng buộc). (giao diện này hữu ích hơn nhiều khi liên kết các đối tượng rời rạc - nghĩa là không phải danh sách).

Triển khai ITypedList và cung cấp mô hình PropertyDescriptor là công việc khó khăn ... do đó nó chỉ được thực hiện rất thường xuyên. Tôi khá quen thuộc với nó, nhưng tôi sẽ không làm điều đó chỉ vì cười ...


Dưới đây là một rất, rất đơn giản thực hiện (tất cả các cột là chuỗi, không có thông báo (qua mô tả), không có xác nhận (IDataErrorInfo), không chuyển đổi (TypeConverter), không hỗ trợ danh sách bổ sung (IBindingList/IBindingListView) , không trừu tượng (IListSource), không có siêu dữ liệu/thuộc tính khác, v.v.):

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

Câu trả lời tuyệt vời, tôi sẽ cho bạn biết cách tôi nhận được ... –

+3

Ouch ... Mắt tôi đang chảy máu. Tôi quay lại bộ sưu tập các tập dữ liệu và cột động: D – Larry

+1

@ControlBreak - lol; một lựa chọn khôn ngoan, tôi nghi ngờ. –

Các vấn đề liên quan