c# 4.0 - c# winforms应用程序中的datagridview / controls中的子级对象属性绑定

本文关键字:对象 属性 绑定 controls 应用程序 winforms datagridview | 更新日期: 2023-09-27 17:51:10

我被困在一个问题,而与绑定对象列表到datagridview或控件工作。实际上我想要的是,我有Person, AddressContactPerson类有3个属性,一个是string类型的Name,一个是Address类型的Add,最后一个是Contact类型的Cont。通过谷歌搜索,我发现我必须创建我创建的CustomTypeDescriptor类,它只适用于ContactAddress的一个类。当我们输入两次时,它显示编译时错误,不能有重复的[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))]

我怎样才能解决这个问题?

在这里我提供的样本代码,我正试图实现,

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        dataGridView1.AutoGenerateColumns = false;
        dataGridView1.Columns.Add("Name", "Name");
        dataGridView1.Columns.Add("City", "City");
        dataGridView1.Columns.Add("ContactName", "ContactName");
        dataGridView1.Columns["Name"].DataPropertyName = "Name";
        dataGridView1.Columns["City"].DataPropertyName = "Add_City";
        dataGridView1.Columns["ContactName"].DataPropertyName = "Cont_ContactName";
        List<Person> PersonList = PersonProxy.GetPersonCollection();
        dataGridView1.DataSource = PersonList;
    }
}

public class PersonProxy
{
    public static List<Person> GetPersonCollection()
    {
        List<Person> persList = new List<Person>();
        persList.Add(new Person
        {
            Name = "Awadhendra",
            Add = new Address
            {
                City = "Allahabad"
            },
            Cont = new Contact
            {
                ContactName = "Awadh"
            }
        });
        persList.Add(new Person
        {
            Name = "Alok",
            Add = new Address
            {
                City = "Allahabad"
            },
            Cont = new Contact
            {
                ContactName = "Alok"
            }
        });
        persList.Add(new Person
        {
            Name = "Ankit",
            Add = new Address
            {
                City = "Lucknow"
            },
            Cont = new Contact
            {
                ContactName = "Ankit"
            }
        });
        persList.Add(new Person
        {
            Name = "Swati",
            Add = new Address
            {
                City = "Lucknow"
            },
            Cont = new Contact
            {
                ContactName = "Awadh"
            }
        });
        return persList;
    }
}

[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))]    
public class Person
{
    public string Name { get; set; }
    public Address Add { get; set; }    ////How to get address and contact both for binding.        
    public Contact Cont { get; set; }  ////Write now am getting Contact
}
public class Address
{
    public string City { get; set; }
}
public class Contact
{
    public string ContactName { get; set; }
}
public class MyTypeDescriptionProvider<T> : TypeDescriptionProvider
{
    private ICustomTypeDescriptor td;
    public MyTypeDescriptionProvider()
        : this(TypeDescriptor.GetProvider(typeof(Person)))
    {
    }
    public MyTypeDescriptionProvider(TypeDescriptionProvider parent)
        : base(parent)
    {
    }
    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        if (td == null)
        {
            td = base.GetTypeDescriptor(objectType, instance);
            td = new MyCustomTypeDescriptor(td, typeof(T));
        }
        return td;
    }
}
public class SubPropertyDescriptor : PropertyDescriptor
{
    private PropertyDescriptor _subPD;
    private PropertyDescriptor _parentPD;
    public SubPropertyDescriptor(PropertyDescriptor parentPD, PropertyDescriptor subPD, string pdname)
        : base(pdname, null)
    {
        _subPD = subPD;
        _parentPD = parentPD;
    }
    public override bool IsReadOnly { get { return false; } }
    public override void ResetValue(object component) { }
    public override bool CanResetValue(object component) { return false; }
    public override bool ShouldSerializeValue(object component)
    {
        return true;
    }
    public override Type ComponentType
    {
        get { return _parentPD.ComponentType; }
    }
    public override Type PropertyType { get { return _subPD.PropertyType; } }
    public override object GetValue(object component)
    {
        return _subPD.GetValue(_parentPD.GetValue(component));
    }
    public override void SetValue(object component, object value)
    {
        _subPD.SetValue(_parentPD.GetValue(component), value);
        OnValueChanged(component, EventArgs.Empty);
    }
}
public class MyCustomTypeDescriptor : CustomTypeDescriptor
{
    Type typeProperty;
    public MyCustomTypeDescriptor(ICustomTypeDescriptor parent, Type type)
        : base(parent)
    {
        typeProperty = type;
    }
    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        PropertyDescriptorCollection cols = base.GetProperties(attributes);
        string propertyName = "";
        foreach (PropertyDescriptor col in cols)
        {
            if (col.PropertyType.Name == typeProperty.Name)
                propertyName = col.Name;
        }
        PropertyDescriptor pd = cols[propertyName];
        PropertyDescriptorCollection children = pd.GetChildProperties();
        PropertyDescriptor[] array = new PropertyDescriptor[cols.Count + children.Count];
        int count = cols.Count;
        cols.CopyTo(array, 0);
        foreach (PropertyDescriptor cpd in children)
        {
            array[count] = new SubPropertyDescriptor(pd, cpd, pd.Name + "_" + cpd.Name);
            count++;
        }
        PropertyDescriptorCollection newcols = new PropertyDescriptorCollection(array);
        return newcols;
    }
}

谢谢,

c# 4.0 - c# winforms应用程序中的datagridview / controls中的子级对象属性绑定

基于MSDN

有两种方法可以将TypeDescriptionProviderTypeDescriptor关联起来:

  • 在设计时,当目标类可以分配适当的TypeDescriptionProviderAttribute标签时。
  • 在运行时,当可以调用TypeDescriptor类的AddProvider方法之一时。这些重载方法要么需要目标对象,要么需要它的类类型。

所以只要在运行时添加它们:

private void Form1_Load(object sender, EventArgs e)
    {
        dataGridView1.AutoGenerateColumns = false;
        dataGridView1.Columns.Add("Name", "Name");
        dataGridView1.Columns.Add("City", "City");
        dataGridView1.Columns.Add("ContactName", "ContactName");
        dataGridView1.Columns["Name"].DataPropertyName = "Name";
        dataGridView1.Columns["City"].DataPropertyName = "Add_City";
        dataGridView1.Columns["ContactName"].DataPropertyName = "Cont_ContactName";
        List<Person> PersonList = PersonProxy.GetPersonCollection();
        //add them here
        System.ComponentModel.TypeDescriptor.AddProvider((new MyTypeDescriptionProvider<Address>()), typeof(Person));
        System.ComponentModel.TypeDescriptor.AddProvider((new MyTypeDescriptionProvider<Contact>()), typeof(Person));
        dataGridView1.DataSource = PersonList;
    }

我发现在。net 4.5中,前面的答案几乎可以工作,但问题是AddProvider方法作为最后一个获胜,所以我们只能看到合同的属性,而不是地址。

解决方案是将提供商链接在一起,这样我们就可以得到…

//add them here
var addressProvider = new MyTypeDescriptionProvider<Address>();
System.ComponentModel.TypeDescriptor.AddProvider(t1, typeof(Person));
System.ComponentModel.TypeDescriptor.AddProvider(new MyTypeDescriptionProvider<Contact>(t1), typeof(Person));