简体   繁体   中英

WinForms DataGridView: Binding an object with a nested object property (expanding columns)

This is a variation of Marc Gravels's answer

I'd extent Marc Gravels's helpful example to view nested objects in a generic way. But System throws an System.Reflection.TargetException.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
public class Author
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
}
public class BookDetails
{
    public string Title { get; set; }
    public int TotalRating { get; set; }
    public int Occurrence { get; set; }
    public Author Author { get; set; }
}
//public class MyBindingSource<T> : BindingSource
class MyList<T> : List<T>, ITypedList
{
    public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
    {
        var origProps = TypeDescriptor.GetProperties(typeof(T));

        List<PropertyDescriptor> newProps = new List<PropertyDescriptor>(origProps.Count);
        foreach (PropertyDescriptor prop in origProps)
        {
            var childProps = TypeDescriptor.GetProperties(prop.GetType());
            if ((childProps.Count == 0) || isSimpleType(prop))
            {
                newProps.Add(prop);
            }
            else
            {
                foreach (PropertyDescriptor childProp in childProps)
                {
                    newProps.Add(new MyPropertyDescriptor(prop, childProp));
                }
            }

        }
        return new PropertyDescriptorCollection(newProps.ToArray());
    }

    private static bool isSimpleType(PropertyDescriptor prop)
    {
        if (prop.PropertyType.BaseType == typeof(ValueType)) return true;
        if (prop.PropertyType == typeof(string)) return true;
        if (prop.PropertyType.BaseType != typeof(Object)) return true;

        return false;
    }

    public string GetListName(PropertyDescriptor[] listAccessors)
    {
        return "";
    }
}
class MyPropertyDescriptor : PropertyDescriptor
{
    private static readonly Attribute[] nix = new Attribute[0];
    private readonly PropertyDescriptor parent;
    private readonly PropertyDescriptor child;
    public MyPropertyDescriptor(PropertyDescriptor parent, PropertyDescriptor child)
        : base(parent.Name + "." + child.Name, nix)
    {
        this.parent = parent;
        this.child = child;
    }
    public override object GetValue(object component)
    {
        return child.GetValue(component);
    }
    public override Type PropertyType
    {
        get { return child.PropertyType; }
    }
    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 parent.ComponentType; }
    }
    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        var author1 = new Author()  { FirstName = "Victor", LastName = "Hugo"  };
        var author2 = new Author() { FirstName = "Moore", LastName = "Thomas" };
        var data = new MyList<BookDetails> { 
            new BookDetails { Title = "abc", TotalRating = 3, Occurrence = 2, Author = author1 }, 
            new BookDetails { Title = "def", TotalRating = 3, Occurrence = 2, Author = author2 }, 
            new BookDetails { Title = "ghi", TotalRating = 3, Occurrence = 2, Author = author1 }, 
            new BookDetails { Title = "jkl", TotalRating = 3, Occurrence = 2, Author = author2 }, 
        };
        Application.Run(new Form
        {
            Controls = { 
                new DataGridView { 
                    Dock = DockStyle.Fill, 
                    DataSource = data 
                } 
            }
        });
    }
}

您应该将prop.GetType()更改为prop.PropertyType

I found the solution by myself:

The error was in the MyPropertyDescriptor!

Correction:

class MyPropertyDescriptor : PropertyDescriptor
{
    private static readonly Attribute[] nix = new Attribute[0];
    private readonly PropertyDescriptor parent;
    private readonly PropertyDescriptor child;
    public MyPropertyDescriptor(PropertyDescriptor parent, PropertyDescriptor child)
        : base(parent.Name + "." + child.Name, nix)
    {
        this.parent = parent;
        this.child = child;
    }
    public override object GetValue(object component)
    {
        var temp = parent.GetValue(component);
        if (temp == null) return null;
        var temp2 = child.GetValue(temp);
        return temp2;
    }
    public override Type PropertyType
    {
        get { return child.PropertyType; }
    }
    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 parent.ComponentType; }
    }
    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM