C# DataGridView 选中所有复选框
问题描述
在程序中尝试选中所有复选框,但出现错误。如果单击顶部的完整选中/释放复选框,同时选中包含复选框的列,则选定区域不会改变。该如何解决?
上面的图片是点击完整版本之后的。
下面是本文的测试代码,函数 dataGridView1_CellPainting() 和 dgvCheckBox_CheckedChanged() 用于完整检查/释放操作。
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;
}
}
}
}
解决方法
请考虑使用数据绑定,DataGridView这可以简化您的操作。通过定义一个Record包含属性的类,当您将该记录添加到这些记录的bool IsChecked绑定列表时,复选框行会自动创建。然后,您可以通过在记录中设置属性来操作该复选框,而无需调用 UI 对象本身。
单击标题单元格:
如果全部选中或未选中,则全部将切换。
如果混合了已选中和未选中,则所有都将被提升为已选中。
示例代码:
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; }
}
}
另一种方法
这种方式,本文未测试:
private void dgvCheckBox_CheckedChanged(object sender, EventArgs e)
{
foreach (DataGridViewRow r in dataGridView1.Rows)
{
if (r.Cells[0] is DataGridViewCheckBoxCell checkbox)
{
dataGridViewDocuments.EndEdit();
}
r.Cells[0].Value = ((CheckBox)sender).Checked;
}
}
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。