2013-01-10 5 views
5

Utknąłem w problemie podczas pracy z listą obiektów wiązania w datagridview lub kontrolkach. Właściwie to, czego chcę, mam klasę powiedzieć Person, Address i Contact. Klasa Person ma 3 właściwości, jedna nazwa typu ciąg, Add typu Adres, a ostatnia to Cont typu Contact. W googlowaniu okazało się, że muszę utworzyć utworzoną przez siebie klasę CustomTypeDescriptor i działa ona tylko dla jednej klasy dla Contact lub dla Address. Kiedy umieszczamy dwa razy, pokazuje błąd kompilacji, który nie może mieć duplikatu [TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))].Powiązanie właściwości obiektu poziomu na poziomie użytkownika w datagridview/kontroli w aplikacji C# winforms

Jak mogę rozwiązać ten problem.

Tutaj przytaczam przykładowy kod, który próbuję wdrożyć

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

Dzięki,

Odpowiedz

3

Na podstawie MSDN

Istnieją dwa sposoby, aby skojarzyć TypeDescriptionProvider z TypeDescriptor :

  • W czasie projektowania, gdy klasie docelowej można przypisać odpowiednią etykietę TypeDescriptionProviderAttribute.
  • W czasie wykonywania, gdy można wywołać jedną z metod AddProvider klasy TypeDescriptor. Te przeciążone metody wymagają albo obiektu docelowego lub jego klasy.

więc wystarczy dodać je do wykonywania:

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

I z .NET 4.5, poprzednia odpowiedź prawie działa znaleźć, ale problemem jest to, że metoda AddProvider działa jako ostatni wygrywa więc widzimy tylko nieruchomości z Kontraktu, ale nie Adres.

Rozwiązaniem jest łańcuch dostawców razem tak otrzymujemy ...

//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)); 
Powiązane problemy