I am stuck in a problem while working with binding object list into datagridview or controls. Actually what I want, I have class say Person
, Address
and Contact
. Person
class have 3 properties one Name of type string, Add
of type Address and last one is Cont
of type Contact
. By googling I found that I have to create CustomTypeDescriptor
class which I created and it works for only one class either for Contact
or for Address
. When we put two times then it shows compile time error that can not have duplicate [TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))]
.
How can I solve this problem.
Here I am providing sample code which I am trying to implement,
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;
}
}
Thanks,
The DataGridView control provides a customizable table for displaying data. The DataGridView class allows customization of cells, rows, columns, and borders through the use of properties such as DefaultCellStyle, ColumnHeadersDefaultCellStyle, CellBorderStyle, and GridColor.
Drag and drop DataGridView control from toolbox to form window. Figure 2. Now choose a data source by right clicking on the DataGridView and then click on Add Project Data Source. We will be adding a new data source to the project right now.
Based on MSDN
There are two ways to associate a
TypeDescriptionProvider
with aTypeDescriptor
:
- At design time, when the target class can be assigned the appropriate
TypeDescriptionProviderAttribute
tag.- At run time, when one of the
AddProvider
methods of theTypeDescriptor
class can be called. These overloaded methods require either the target object or its class type.
So Just add them in runtime:
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;
}
I found with .NET 4.5, the previous answer almost works, but the issue is that the AddProvider method acts as a last one wins, so we only see properties from Contract but not Address.
The solution is to chain the providers together so we get...
//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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With