Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
404 views
in Technique[技术] by (71.8m points)

c# - WinForms DataGridView - databind to an object with a list property (variable number of columns)

I have a .NET class I'd like to show in a DataGridView, and the default databinding - setting the DGV's DataSource to the object - produces 90% of my requirements (i.e. it's outputting the public properties correctly and I can add sorting easily).

However, one of the properties I need to bind is a List which contains data which needs to be in separate columns after the other databound items. I'm stuck on how best to implement this.

My class looks something like this:

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

Ideally, I'd be able to expand that Rating property into a number of numeric columns to give an output like this at runtime:

Title | Total Rating | Occurrence | R1 | R2 | R3 ... RN

It would also be useful to have Total Rating be calculated as the sum of all the individual ratings, but I'm updating that manually at the moment without issue.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Like this?

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
                }
            }
        });

    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...