How does data binding work with a DataTable?

Suppose I have a DataGridView WinForms control, and I bind the data to a custom IList of the type, for example:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

private void Form1_Load(object sender, EventArgs e)
{
    var data = new ArrayList();

    data.Add(new Person("Bob", 25));
    data.Add(new Person("Alice", 23));

    this.dataGridView1.DataSource = data;
}

This displays the list items with the column names "Name" and "Age" that have been clearly identified (by reflection) from the public properties of the list items. (The first paragraph is in accordance with my tests.)

But if I do the same using a DataTable:

DataTable dt = new DataTable();

dt.Columns.Add("Name");
dt.Columns.Add("Row");

dt.Rows.Add("Bob", 25);
dt.Rows.Add("Alice", 23);

this.dataGridView1.DataSource = dt;

... how does a DataGridView know how to use DataTable columns instead of its public properties? Neither DataTable nor DataRow seem to implement any interface providing this information. Or does a DataGridView know about the DataTable type and treats this type of data source differently?

, , , "" , .

+4
3

. "" ICustomTypeDescriptor, DataRowView ( DataRow). , PropertyDescriptor:

public class MyPropertyDescriptor<TComponent, TValue> : PropertyDescriptor
{
    private readonly Func<TComponent, TValue> getter;

    private readonly Action<TComponent, TValue> setter;

    public MyPropertyDescriptor(string name, Func<TComponent, TValue> getter, Action<TComponent, TValue> setter)
        : base(name, null)
    {
        this.getter = getter;
        this.setter = setter;
    }

    public override bool CanResetValue(object component)
    {
        return true;
    }

    public override object GetValue(object component)
    {
        return getter((TComponent)component);
    }

    public override void ResetValue(object component)
    {
        setter((TComponent)component, default(TValue));
    }

    public override void SetValue(object component, object value)
    {
        setter((TComponent)component, (TValue)value);
    }

    public override bool ShouldSerializeValue(object component)
    {
        return true;
    }

    public override Type ComponentType
    {
        get { return typeof(TComponent); }
    }

    public override bool IsReadOnly
    {
        get { return false; }
    }

    public override Type PropertyType
    {
        get { return typeof(TValue); }
    }
}

Person ICustomTypeDescriptor:

public class Person : ICustomTypeDescriptor 
{
    public string Name { get; set; }

    public int Age { get; set; }

    /* ... Unimplemented ICustomTypeDescriptor methods left out ... */

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[]
                                                    {
                                                        new MyPropertyDescriptor<Person, string>("My Name", p => p.Name, (p, s) => p.Name = s), 
                                                        new MyPropertyDescriptor<Person, int>("My Age", p => p.Age, (p, i) => p.Age = i)
                                                    };

        return new PropertyDescriptorCollection(propertyDescriptors);
    }
}

GridView ...

enter image description here

, , , . , , , , ( , ).

+3

DataSource DataGridView IListSource, DataTable DataSet.

MSDN , .

+2
GridView1.DataSource = dt;
GridView1.DataBind();
+1

All Articles