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