A Quick way to Build a ‘Select all’ Button with WinForms DataGridView

Vitalii Symon, 08 October 2010

The problem seems to be so small that it makes no sense to post about it… until you try to solve it.

A Quick way to Build a ‘Select all’ Button with WinForms DataGridView

This is what we want to get.

A WinForms grid can contain large number of different controls and work with any kind of data, so it’s very easy to get lost among long list of events.

The main trouble is that when CellValueChanged, CellValidated, CellEndEdit events (which are the most popular) are raised, the focus is lost, so our checkbox will not look realistic.

There are several solutions to this problem including making the column read-only and handling clicks using your own code. However, if you search well enough you’ll find the CurrentCellDirtyStateChanged event, which is raised every time any cell is marked as dirty which means editing has started.

We’ll use this code to test:

        private TestItem[] _items;
        public Form1()
        {
            InitializeComponent();
 
            _items = new[]{
                new TestItem{ Text = "One", Ticked = true},
                new TestItem{ Text = "Two", Ticked = true},
                new TestItem{ Text = "Three", Ticked = true},
            };

            dataGridView1.DataSource = _items;

        }

    class TestItem
    {
        public bool Ticked { get; set; }
        public string Text { get; set; }
    }

Since the checkbox has two states we can finish editing once we’ve started it – value is already changed and no further modifications will happen. Let’s add handler, and you get this

        private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
        }

Then we add code that will reflect current column state on the primary checkbox

        private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            checkBoxSelectAll.ThreeState = true;
            checkBoxSelectAll.CheckState = CheckState.Indeterminate;
 
            if (_items.All(c => c.Ticked))
                checkBoxSelectAll.CheckState = CheckState.Checked;

            if (_items.All(c => !c.Ticked))
                checkBoxSelectAll.CheckState = CheckState.Unchecked;
        }

It still works after losing focus only because the value from the cell is transferred to object after editing has finished. We can force finalizing using EndEdit() method. Like this:

   private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
   {
       if (dataGridView1.CurrentCell != null && dataGridView1.CurrentCell.ColumnIndex != 0)
             return;
 
       dataGridView1.EndEdit();

Also, it makes sense to add check for column number, otherwise the user will not be able to enter more than one character to textbox.

And now the easiest part – adding checkbox handler:

        private void checkBoxSelectAll_Click(object sender, EventArgs e)
        {
            checkBoxSelectAll.ThreeState = false;
 
            foreach (var i in _items)
                i.Ticked = checkBoxSelectAll.Checked;
 
            dataGridView1.Refresh();
        }

I hope I saved you a bit of your time in searching for an appropriate method to handle checkbox event. You can download sample from here.