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;

}

}

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
FAREWELL0007526 分钟前
Unity基础学习(十五)核心系统——音效系统
学习·unity·c#·游戏引擎
zimoyin2 小时前
Java 快速转 C# 教程
java·开发语言·c#
向宇it2 小时前
【unity游戏开发——编辑器扩展】使用MenuItem自定义菜单栏拓展
开发语言·ui·unity·c#·编辑器·游戏引擎
动感光博2 小时前
Unity碰撞检测(射线投射、胶囊体投射)、交互(图层、掩码)
unity·c#·游戏引擎·游戏程序·动画
动感光博5 小时前
Unity(URP渲染管线)的后处理、动画制作、虚拟相机(Virtual Camera)
开发语言·人工智能·计算机视觉·unity·c#·游戏引擎
hie988947 小时前
C#与KepOPC通讯
开发语言·c#
hweiyu008 小时前
C#学习教程(附电子书资料)
开发语言·学习·c#
qq_2979080113 小时前
c#车检车构客户管理系统软件车辆年审短信提醒软件
sqlserver·c#·开源软件
酷炫码神14 小时前
C#数组与集合
开发语言·c#