Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Child level object property binding in datagridview / controls in c# winforms application

Tags:

c#

c#-4.0

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,

like image 392
Awadhendra Avatar asked Jan 10 '13 13:01

Awadhendra


People also ask

Which is a property of the DataGridView Control?

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.

How to use DataGridView Control in c#?

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.


2 Answers

Based on MSDN

There are two ways to associate a TypeDescriptionProvider with a TypeDescriptor:

  • At design time, when the target class can be assigned the appropriate TypeDescriptionProviderAttribute tag.
  • At run time, when one of the AddProvider methods of the TypeDescriptor 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;
    }
like image 191
Bolu Avatar answered Sep 28 '22 11:09

Bolu


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));
like image 37
Paul Hatcher Avatar answered Sep 28 '22 13:09

Paul Hatcher