Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataGridView Columns not generating from Custom DataSource

I have written a class that implements the IBindingListView interface, BindableList<T> : IBindingListView.

_abilityList = new BindableList<Ability>();
dataGridViewAbility.AutoGenerateColumns = true;
dataGridViewAbility.DataSource = _abilityList;

For some reason the DataGridView does not Generate Columns, so when I add data to my BindableList<T> the DataGridView throws an error stating i need to add columns first.

What makes this weird is that if I add an Object to my BindableList<T> then the columns are generated just find. I also switched out My class for BindingList<T>, add nothing to it and the columns generate just fine.

I am at a loss as to why the DataGridView will not Generate the Columns from my Generic Binding List when it is empty. The Framework knows what the type of the generic is when the program builds.

UPDATE:

Ability Class

class Ability
{
    public Int32 ID { get; set; }
    public Int32 Generation { get; set; }
    public String Name { get; set; }
    public String Effect { get; set; }
}

I do not see why people are having trouble understanding this but i have made a new Winform App that still has the same problem.

private BindableList<Ability> _abilityList;

    public Form1()
    {
        InitializeComponent();

        _abilityList = new BindableList<Ability>();

        Button b = new Button();
        b.Location = new Point(0, 0);
        b.Click += new EventHandler(buttonGetData_Click);
        this.Controls.Add(b);

        DataGridView _grid = new DataGridView();
        _grid.Location = new Point(100, 0);
        _grid.AutoGenerateColumns = true;
        _grid.DataSource = _abilityList;
        this.Controls.Add(_grid);
    }

    private void buttonGetData_Click(object sender, EventArgs e)
    {
        _abilityList.Add(new Ability());
    }

OnListChanged Event

protected virtual void OnListChanged(ListChangedEventArgs e)
{
    if (ListChanged != null)
    {
        ListChanged(this, e);
    }
}

When the line _abilityList.Add runs, this fires the ListChanged(this, e);. This runs and the DataGridView throws and Error, No Columns added to View. If I add and Object to the BindableList<T> first before Assigning it as the DataSource the Columns will Generate.

like image 902
Olin Causey Avatar asked May 06 '26 01:05

Olin Causey


1 Answers

Simply assigning the DataGridView.DataSource property does not generate the columns right away. In my experience, if you need the DataGridViewColumns right away, then there are 4 critical lines of code to force the columns to be created:

        DataGridView dgv = new DataGridView() { Dock = DockStyle.Fill };
        BindingList<Ability> list = new BindingList<Ability>();
        dgv.AutoGenerateColumns = true;
        dgv.DataSource = list;

        int colCount = dgv.Columns.Count; // 0
        //--------
        // force columns to be created
        using (var g = dgv.CreateGraphics()) {}
        using (var f = new Form()) {
            f.Controls.Add(dgv);
            f.Controls.Remove(dgv);
        }
        //--------
        int colCount2 = dgv.Columns.Count; // 4

Edit: Alternative approach which is much faster, especially when properties on the DataGridViewColumns (e.g. AutoSizeMode and SortMode) need to be set.

public static void Refresh(DataGridView view, DataTable table) {
    bool origAuto = view.AutoGenerateColumns;
    view.AutoGenerateColumns = true;
    view.DataSource = table;
    view.BindingContext = new BindingContext();
    view.AutoGenerateColumns = origAuto;
}
like image 197
Loathing Avatar answered May 08 '26 05:05

Loathing