2

I have a datagridview where all the columns are bound except for one checkbox column. In my form's OnLoad I go through the rows in my dataGridView and set DataGridViewCheckBoxCell.Value = true for each row.

I've verified at the end of my OnLoad that all the DataGridViewCheckBoxCells that I set still have the values I gave them, but once the dataGridView is displayed all the selected values and checkbox values I set get reset.

BenCamps
  • 1,694
  • 15
  • 25

1 Answers1

2

Apparently , when a DataGridView becomes visible (Visible = true), OnBindingContextChanged gets called causing the internal data connection to be reset and reset the values on all the cells.

So instead of setting the values of cell in my form's OnLoad I set VirtualMode = true on my data grid and override OnCellValueNeeded where I can provide the check box cell's value on demand.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace MyControls
{
public class SelectedItemsGridView : DataGridView
{
    private IList _SelectedItems;
    public IList SelectedItems 
    {
        get { return _SelectedItems; }
        set
        {
            _SelectedItems = value;
            ClearSelection();
            Refresh();
        }
    }

    public SelectedItemsGridView()
        : base()
    {
        SelectionMode = DataGridViewSelectionMode.FullRowSelect;
        RowHeadersVisible = false;
        VirtualMode = true;
        ////Columns.Add(new DataGridViewCheckBoxColumn(false) { 
        //    AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader,
        //    HeaderText = "Select"});
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        if (DesignMode == true) { return; }
        Columns.Insert(0, new DataGridViewCheckBoxColumn(false)
        {
            AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader,
            HeaderText = "Select"
        });
    }

    public bool IsItemSelected(object obj)
    {
        if (SelectedItems == null) { return false; }
        return SelectedItems.Contains(obj);
    }

    protected override void OnCellValueNeeded(DataGridViewCellValueEventArgs e)
    {
        base.OnCellValueNeeded(e);
        if (e.ColumnIndex == 0)
        {
            e.Value = IsItemSelected((this.DataSource as IList)[e.RowIndex]);
        }
    }

    protected override void OnCellContentClick(DataGridViewCellEventArgs e)
    {
        base.OnCellContentClick(e);
        if (e.RowIndex == -1) { return; }
        Object item = ((IList)DataSource)[e.RowIndex];
        if(e.ColumnIndex == 0)
        {
            var cellValue = this[e.ColumnIndex, e.RowIndex].Value;
            if (cellValue != null && (bool)cellValue == true)
            {
                SelectedItems.Remove(item);

            }
            else if (cellValue != null && (bool)cellValue == false)
            {
                SelectedItems.Add(item);
            }
        }
    }
}

}

BenCamps
  • 1,694
  • 15
  • 25
  • 2
    Sounds like you have a solution which is good, but you should not need to do this - A standard unbound checkbox column will keep values that you programatically set in either an overridden OnLoad method or in a DataBindingComplete handler. If you feel like posting code from your form myself or others will happily look into what is going on. – David Hall Jun 20 '12 at 17:50
  • 1
    My DataGrid is in a TabPage and that may be making the DataGridView act slightly odd, but my problem wasn't that the checkbox column wasn't holding values all the time, it was just when the gridView went from not visable to visable for the first time. I'm able to verify that my checkbox column values are being set before I switch to the tabPage containing the dataGridView but when the dataGridView gets displayed all the checkbox column cell values get set back to null. Once the dataGridView is displayed, when I set the checkbox cells values they hold their values. – BenCamps Jun 20 '12 at 21:10
  • 3
    Ah ok - that makes a big difference. As far as I can tell this is a feature of the grid that is very close to a bug (I've seen posts from the DGV project manager asking for bug reports related to it). The grid does not databind until it is visible - when it does databind this blows away your data in it. I can think of two options - making the changes in a DataBindingComplete handler works, and you can also add a column for the checks to your datasource. – David Hall Jun 20 '12 at 21:37
  • Wow, thank you both so much! I was really confused because I was adding an unbound `DataGridViewCheckBoxColumn` and initializing all of the values to `false`. Later on in a different function I was checking those values and they were always `null`. I couldn't fathom how they were `null` because I just initialized all of them to `false`! Sure enough, between these events we are setting the `DataGridView` to be visible. How did you know/figure out that making the `DataGridView` visible destroys unbound values? – Derek Dec 02 '15 at 18:37
  • Wouldn't it be nice if Microsoft's documentation mentioned this issue? [How to: Add an Unbound Column to a Data-Bound Windows Forms DataGridView Control](https://msdn.microsoft.com/en-us/library/zkatshfa(v=vs.110).aspx) – Derek Dec 02 '15 at 18:38