Search code examples
c#winformsdata-bindingdatagridviewbindingsource

DataGridView programatic selection of new item does not update other data-bound controls


I have a DataGridView and a number of controls (for editing) all bound to a BindingSource. Everything works as expected - clicking on an entry in the DataGridView causes the bound edit controls to display and edit the selected item. What I want to be able to do is have newly created items be automatically selected in the DataGridView, with the edit controls also bound to the newly created data. To do this, I have implemented a handler for DataGridView.RowsAdded, like so:

private void dataGridViewBeasts_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
    // Force newly created items to be selected
    dataGridViewBeasts.Rows[e.RowIndex].Selected = true;
}

This works superficially, with the newly created items being selected in the DataGridView. However, the edit controls persist in referring to the item that was selected prior to creating a new item. How can I encourage them to point to the newly selected item?


Solution

  • Assumption:

    You are adding a new row to the underlying DataSource, not directly to the DataGridView.

    Result:

    The problem you are encountering here is that the binding on all of your editing controls are tied to the DataGridView.CurrentRow bound item - which is a get only property and is indicated by an arrow in the row header column.

    Changing the CurrentRow is discussed in Selecting a row in a DataGridView and having the arrow on the row header follow.

    So it should be as simple as setting the CurrentCell to Cell[0] of the newly added row. Except...

    Setting CurrentCell in the DataGridView.RowsAdded event will fail. Conceptually, it works - the new row becomes the CurrentRow. But after that event is finished, debugging will show that the CurrentRow is immediately reset to its prior value. Instead, set the CurrentCell after your code to add the new row. For example when BindingSource.DataSource:

    Is a DataTable:

    DataTable dt = theBindingSource.DataSource as DataTable;
    dt.Rows.Add("New Row", "9000");
    
    dataGridView1.CurrentCell = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0];
    

    Or a List<Example>:

    List<Example> list = theBindingSource.DataSource as List<Example>;
    list.Add(new Example() { Foo = "New Row", Bar = "9000" });
    
    // Reset the bindings.
    dataGridView1.DataSource = null;
    dataGridView1.DataSource = theBindingSource;
    
    dataGridView1.CurrentCell = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0];