WinForms DataGridView – 数据绑定到具有列表属性的对象(可变列数)

我有一个.NET类,我想在DataGridView中显示,默认的数据绑定 – 将DGV的DataSource设置为对象 – 产生90%的需求(即它正确输出公共属性,我可以轻松添加排序) 。

但是,我需要绑定的属性之一是List,其中包含需要在其他数据绑定项之后的单独列中的数据。 我坚持认为如何最好地实现这一点。

我的课看起来像这样:

public class BookDetails { public string Title { get; set; } public int TotalRating { get; set; } public int Occurrence { get; set; } public List Rating { get; set; } } 

理想情况下,我可以将Rating属性扩展为多个数字列,以便在运行时提供如下输出:

标题| 总评分| 发生| R1 | R2 | R3 …… RN

将总评分计算为所有单个评级的总和也是有用的,但我现在手动更新该评级没有问题。

像这样?

 using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows.Forms; public class BookDetails { public string Title { get; set; } public int TotalRating { get; set; } public int Occurrence { get; set; } public List Rating { get; set; } } class BookList : List, ITypedList { public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) { var origProps = TypeDescriptor.GetProperties(typeof(BookDetails)); List newProps = new List(origProps.Count); PropertyDescriptor doThisLast = null; foreach (PropertyDescriptor prop in origProps) { if (prop.Name == "Rating") doThisLast = prop; else newProps.Add(prop); } if (doThisLast != null) { var max = (from book in this let rating = book.Rating where rating != null select (int?)rating.Count).Max() ?? 0; if (max > 0) { // want it nullable to account for jagged arrays Type propType = typeof(int?); // could also figure this out from List in // the general case, but make it nullable for (int i = 0; i < max; i++) { newProps.Add(new ListItemDescriptor(doThisLast, i, propType)); } } } return new PropertyDescriptorCollection(newProps.ToArray()); } public string GetListName(PropertyDescriptor[] listAccessors) { return ""; } } class ListItemDescriptor : PropertyDescriptor { private static readonly Attribute[] nix = new Attribute[0]; private readonly PropertyDescriptor tail; private readonly Type type; private readonly int index; public ListItemDescriptor(PropertyDescriptor tail, int index, Type type) : base(tail.Name + "[" + index + "]", nix) { this.tail = tail; this.type = type; this.index = index; } public override object GetValue(object component) { IList list = tail.GetValue(component) as IList; return (list == null || list.Count <= index) ? null : list[index]; } public override Type PropertyType { get { return type; } } public override bool IsReadOnly { get { return true; } } public override void SetValue(object component, object value) { throw new NotSupportedException(); } public override void ResetValue(object component) { throw new NotSupportedException(); } public override bool CanResetValue(object component) { return false; } public override Type ComponentType { get { return tail.ComponentType; } } public override bool ShouldSerializeValue(object component) { return false; } } static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); var data = new BookList { new BookDetails { Title = "abc", TotalRating = 3, Occurrence = 2, Rating = new List {1,2,1}}, new BookDetails { Title = "def", TotalRating = 3, Occurrence = 2, Rating = null }, new BookDetails { Title = "ghi", TotalRating = 3, Occurrence = 2, Rating = new List {3, 2}}, new BookDetails { Title = "jkl", TotalRating = 3, Occurrence = 2, Rating = new List()}, }; Application.Run(new Form { Controls = { new DataGridView { Dock = DockStyle.Fill, DataSource = data } } }); } }