Home > database >  How can I select all checkboxes with DataGridView of C#?
How can I select all checkboxes with DataGridView of C#?

Time:05-19

I'm trying to select all checkboxes, but It have an error.

If I click the full check/release checkbox at the top while a column containing a checkbox is selected, the selected area doesn't change.

How should I solve it?

enter image description here

The picture above is after clicking the full release.

This is my test code.

The function dataGridView1_CellPainting() and dgvCheckBox_CheckedChanged() are used for full check/release operation.

namespace TestWinForm
{
    public partial class Form1 : Form
    {
        List<string> saved_file_names = new List<string>();
        int table_index = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void add_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "열기";
            ofd.Filter =  "txt파일 | *.txt";
            ofd.Multiselect = true; //  파일 다중 선택

            DialogResult dr = ofd.ShowDialog();

            if (dr == DialogResult.OK)
            {
                foreach (string file_name in ofd.FileNames)
                {
                    //  1. 중복체크
                    if (saved_file_names.Contains(file_name))
                        continue;

                    //  2. 중복되지않은 파일들을 추가.
                    dataGridView1.Rows.Add();
                    dataGridView1.Rows[table_index].Cells[1].Value = table_index   1;
                    dataGridView1.Rows[table_index].Cells[2].Value = file_name;
                    saved_file_names.Add(file_name);
                    dataGridView1.Rows[table_index].Cells[3].Value = "none";
                    table_index  ;
                }
            }
        }

        private void delete_Click(object sender, EventArgs e)
        {
            bool is_checked = false;
            List<int> delete_index = new List<int>();
            for (int i = 0; i < table_index; i  )
            {
                if (Convert.ToBoolean(dataGridView1.Rows[i].Cells[0].Value) == true)
                    delete_index.Add(i);
            }

            if (delete_index.Count == 0)
                return;

            delete_index.Reverse();

            foreach (var index in delete_index)
            {
                table_index--;
                saved_file_names.RemoveAt(index);
                dataGridView1.Rows.RemoveAt(index);
            }
        }

        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (e.ColumnIndex == 0 && e.RowIndex == -1)
            {
                e.PaintBackground(e.ClipBounds, false);
                Point pt = e.CellBounds.Location;

                int nChkBoxWidth = 15;
                int nChkBoxHeight = 15;
                int offsetx = (e.CellBounds.Width - nChkBoxWidth) / 2;
                int offsety = (e.CellBounds.Height - nChkBoxHeight) / 2;

                pt.X  = offsetx;
                pt.Y  = offsety;

                CheckBox cb = new CheckBox();

                cb.Size = new Size(nChkBoxWidth, nChkBoxHeight);
                cb.Location = pt;
                cb.Checked = true;
                cb.CheckedChanged  = new EventHandler(dgvCheckBox_CheckedChanged);

                ((DataGridView)sender).Controls.Add(cb);

                e.Handled = true;

            }

        }

        private void dgvCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            foreach (DataGridViewRow r in dataGridView1.Rows)
            {
                r.Cells[0].Value = ((CheckBox)sender).Checked;
            }
        }

    }
}

CodePudding user response:

Please consider using Data Binding with your DataGridView which can simplify what you're trying to do. By defining a Record class with your bool IsChecked property, the checkbox row is created automatically when you add that record to a binding list of those records. Then you can manipulate that check by setting the property in your record instead of making calls on the UI object itself.

Clicking the header cell :

  • If All are either checked or unchecked then all will toggle.
  • If there is a mix of checked and unchecked, then all will be promoted to checked.

Here's a working sample on GitHub.

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;

namespace dgv_ac
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Wait for the main form to be created, then attach 
        /// your Binding List as the data source of the DGV
        /// </summary>
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            dataGridView1.DataSource = this.DataSource;
            initDGV();
        }

        private void initDGV()
        {
            dataGridView1.AllowUserToAddRows = false;

            // Now you can populate the DataGridView simply
            // by adding some records to the list.
            for (int i = 0; i < 5; i  )
            {
                DataSource.Add(new Record { Number = i, FileName = $"MyFile_{i}.txt" });
            }


            // Once the first record is added, the Columns information is
            // available and we can do column formatting.
            dataGridView1.Columns[nameof(Record.FileName)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            var checkboxColumn = dataGridView1.Columns[nameof(Record.IsChecked)];
            checkboxColumn.HeaderText = string.Empty;
            checkboxColumn.Width = 40;
            dataGridView1.CellClick  = onCellClick;
            dataGridView1.CellContentClick  = onCellContentClick;
        }

        /// <summary>
        /// Detect check box click and end the edit mode in this case.
        /// </summary>
        private void onCellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if(e.RowIndex != -1)
            {
                var cell = dataGridView1[e.ColumnIndex, e.RowIndex];
                if(cell is DataGridViewCheckBoxCell checkbox)
                {
                    dataGridView1.EndEdit();
                }
            }
        }


        /// <summary>
        /// Detect header click and set the records accordingly.
        /// </summary>
        private void onCellClick(object sender, DataGridViewCellEventArgs e)
        {
            if(e.RowIndex == -1)
            {
                switch (dataGridView1.Columns[e.ColumnIndex].Name)
                {
                    case nameof(Record.IsChecked):
                        if (DataSource.Any())   // Check to see if there are any records at all.
                        {
                            if(DataSource.Count(record=>record.IsChecked) == DataSource.Count)
                            {
                                // This block says thet're all chacked or all unchecked.
                                if(DataSource.First().IsChecked) // then they all are
                                {
                                    setAll(false);
                                }
                                else
                                {
                                    setAll(true);
                                }
                            }
                            else setAll(true); // If they're mixed, make them all checked.
                        }
                        break;
                }
            }
            void setAll(bool value)
            {
                foreach (var record in DataSource)
                {
                    record.IsChecked = value;
                }
                Refresh();
            }
        }

        public BindingList<Record> DataSource = new BindingList<Record>();
    }

    
    // This is the record class that will provide column 
    // information to the DataGridView automatically.
    public class Record
    {
        public int Number { get; set; }
        public bool IsChecked { get; set; }
        public string FileName { get; set; }
    }
}
  • Related