【问题标题】:Child level object property binding in datagridview / controls in c# winforms applicationc# winforms应用程序中datagridview /控件中的子级对象属性绑定
【发布时间】:2012-12-24 21:48:36
【问题描述】:

在将对象列表绑定到 datagridview 或控件时遇到问题。实际上我想要什么,我有课说PersonAddressContactPerson 类有 3 个属性,一个是字符串类型的名称,一个是地址类型的 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# c#-4.0


    【解决方案1】:

    基于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;
        }
    

    【讨论】:

      【解决方案2】:

      我发现在 .NET 4.5 中,之前的答案几乎可以工作,但问题是 AddProvider 方法作为最后一个获胜者,所以我们只能看到来自 Contract 的属性,而不是 Address。

      解决方案是将提供者链接在一起,以便我们得到...

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-23
        • 2011-08-18
        • 2011-02-20
        • 1970-01-01
        • 1970-01-01
        • 2013-10-05
        • 2010-12-21
        相关资源
        最近更新 更多