2011-01-17 10 views
9

Bir DataGridView'da göstermek istediğim bir .NET sınıfım var ve varsayılan veri bağlama - DGV'nin DataSource'ını nesneye ayarlama - üretir İhtiyaçlarımın% 90'ı (yani, kamu özelliklerinin doğru şekilde çıkarılması ve kolayca sıralamayı ekleyebilirim). Bununla birlikte, bağlamanız gereken özelliklerden biri, diğer veri maddelerinden sonra ayrı sütunlarda olması gereken verileri içeren bir Liste'dir. Bunu en iyi nasıl uygulayacağım.WinForms DataGridView - bir liste özelliğine sahip bir nesneye veri (sütunların değişken sayısı)

Başlık:

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

İdeal olarak, ben zamanında böyle bir çıkış vermek sayısal sütunlar bir dizi içine Puanlama özelliğini genişletmek mümkün olurdu:

Benim sınıf şuna benzer | Toplam Değerlendirme | Oluşumu | R1 | R2 | R3 ... RN

Ayrıca, Toplam Derecelendirmenin tüm bireysel derecelendirmelerin toplamı olarak hesaplanmasını sağlamak yararlı olacaktır, ancak şu anda sorun çıkarmadan el ile güncellemeyi yapıyorum.

+0

Tür için bir TypeDescriptor (veya belki TypeConverter) uygulamak zorundasınız. Ne yapacağını biliyorsanız, oldukça önemsiz. Maalesef yazdığım güzel bir örnek şu anda işte. – leppie

+0

@leppie - TypeConverter burada uygulanmaz; aslında, ITypedList muhtemelen en kolay olanıdır; bundan sonra - TypeDescriptionProvider (yazılan bir liste için ICustomTypeDescriptor kullanmayacağından beri) –

+1

@leppie - çerçevenin bu karanlık köşesi ile karmakarışık çılgınca bildiğim iki aptal olmalıyız, p –

cevap

18

Bunu beğendiniz mi?

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<int> Rating { get; set; } 
} 
class BookList : List<BookDetails>, ITypedList 
{ 

    public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) 
    { 
     var origProps = TypeDescriptor.GetProperties(typeof(BookDetails)); 
     List<PropertyDescriptor> newProps = new List<PropertyDescriptor>(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<T> 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<int> {1,2,1}}, 
      new BookDetails { Title = "def", TotalRating = 3, Occurrence = 2, Rating = null }, 
      new BookDetails { Title = "ghi", TotalRating = 3, Occurrence = 2, Rating = new List<int> {3, 2}}, 
      new BookDetails { Title = "jkl", TotalRating = 3, Occurrence = 2, Rating = new List<int>()}, 
     }; 
     Application.Run(new Form 
     { 
      Controls = { 
       new DataGridView { 
        Dock = DockStyle.Fill, 
        DataSource = data 
       } 
      } 
     }); 

    } 
} 
+0

(Ben de tüm "liste erişimci" şey üzerinde glossed ettik - eğer * ihtiyacım varsa, * sadece, bu zincirden her çağrıyı takip eden bir durum) –

+0

+1 Düşündüğümden biraz daha karmaşık, Listedeki değişken miktarda ürün olması nedeniyle :) – leppie

+0

Mükemmel! benim için bir çekicilik gibi çalışır. Çok teşekkürler :) – vitorbal

İlgili konular