6

オブジェクトリストをdatagridviewまたはコントロールにバインドしているときに問題が発生します。実は私が欲しいのは、クラスに言ってもらいPersonAddressそしてContactPersonクラスには3つのプロパティがあります。1つは文字列型の名前、Add1つはアドレス型、最後の1つはContタイプContactです。グーグルで調べたところ、自分で作成しCustomTypeDescriptorたクラスを作成する必要があり、それはforContactまたはforのいずれかの1つのクラスでのみ機能することがわかりましたAddress。2回置くと、重複できないコンパイル時エラーが表示されます[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;
    }
}

ありがとう、

4

2 に答える 2

3

MSDNに基づく

TypeDescriptionProvideraをTypeDescriptor:に関連付けるには2つの方法があります。

  • 設計時に、ターゲットクラスに適切な TypeDescriptionProviderAttributeタグを割り当てることができる場合。
  • 実行時、クラスのAddProviderメソッドの1つをTypeDescriptor呼び出すことができるとき。これらのオーバーロードされたメソッドには、ターゲットオブジェクトまたはそのクラスタイプのいずれかが必要です。

したがって、実行時にそれらを追加するだけです。

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;
    }
于 2013-01-10T14:11:03.743 に答える
1

.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));
于 2014-12-05T13:00:48.333 に答える