views:

621

answers:

2

I added datagridview to my win forms app and I also added one Check Box for marking rows. The CheckBox works as I expected until the user sorts the DataGridView. After the sort the previous selection of checkbox column is lost.

Is there a way I can make my datagridview remember which row is selected after sorting?

+1  A: 

I'm surprised that that happens, but if there's no other way around it in a worst case you could set the sorting to programmatic and then handle when the user clicks on the column header, save a list of which items are checked, do the sorting programmatically and then check any items that should be checked.

ho1
I was surprised too, At firs I was thinking that I am doing something wrong then I fund this article http://www.dotnetspark.com/kb/Content.aspx?id=151 and spot the same behavior of DataGridView
adopilot
+2  A: 

You have two options to solve this issue.

The first and possibly the most simply is to bind your checkbox column to your datasource. For example, if you are using a DataTable as your datasource, adding a boolean column will create a checkbox on your DataGridView that will sort and not lose the checked state.

If this is not an option then you the correct way of addressing the problem is to set your DataGridView to Virtual mode and maintain a cache of your checkbox values.

Check out the excellent DataGridView FAQ for an example of how to do this. I've also provided the code below but do check out the FAQ:

private System.Collections.Generic.Dictionary<int, bool> checkState;
private void Form1_Load(object sender, EventArgs e)
{
    dataGridView1.AutoGenerateColumns = false;
    dataGridView1.DataSource = customerOrdersBindingSource;

    // The check box column will be virtual.
    dataGridView1.VirtualMode = true;
    dataGridView1.Columns.Insert(0, new DataGridViewCheckBoxColumn());

    // Initialize the dictionary that contains the boolean check state.
    checkState = new Dictionary<int, bool>();
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    // Update the status bar when the cell value changes.
    if (e.ColumnIndex == 0 && e.RowIndex != -1)
    {
        // Get the orderID from the OrderID column.
        int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
        checkState[orderID] = (bool)dataGridView1.Rows[e.RowIndex].Cells[0].Value;

}

private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    // Handle the notification that the value for a cell in the virtual column
    // is needed. Get the value from the dictionary if the key exists.

    if (e.ColumnIndex == 0)
    {
        int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
        if (checkState.ContainsKey(orderID))
        {
            e.Value = checkState[orderID];
        }
        else
            e.Value = false;
    }

}

private void dataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
{
    // Handle the notification that the value for a cell in the virtual column
    // needs to be pushed back to the dictionary.

    if (e.ColumnIndex == 0)
    {
        // Get the orderID from the OrderID column.
        int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;

        // Add or update the checked value to the dictionary depending on if the 
        // key (orderID) already exists.
        if (!checkState.ContainsKey(orderID))
        {
            checkState.Add(orderID, (bool)e.Value);
        }
        else
            checkState[orderID] = (bool)e.Value;
    }
}
David Hall
Thanx on answer also FAQ, You are correct about binding boolean column to datasource, One more question ? Should I carry boolean column from original datasource (StoredProc) or it is better way to add that at client level before binding data to my grid
adopilot