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;

}

}

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

相关推荐
Rose 使者2 小时前
全球IP归属地查询接口如何用C#进行调用?
c#·api·ip地址
~plus~4 小时前
Harmony核心:动态方法修补与.NET游戏Mod开发
开发语言·jvm·经验分享·后端·程序人生·c#
htj104 小时前
C# 使用正则表达式
正则表达式·c#
~plus~4 小时前
WPF八大法则:告别模态窗口卡顿
开发语言·经验分享·后端·程序人生·c#
就是有点傻4 小时前
使用WPF的Microsoft.Xaml.Behaviors.Wpf中通用 UI 元素事件
c#
qq_297908015 小时前
C#报价系统陈列展示成本核算系统项目管理系统纸品非纸品报价软件
sqlserver·c#·.net·开源软件
CoderIsArt14 小时前
C#中的CLR属性、依赖属性与附加属性
c#
IGP918 小时前
20250606-C#知识:委托和事件
开发语言·c#
Kookoos19 小时前
ABP VNext 与 Neo4j:构建基于图数据库的高效关系查询
数据库·c#·.net·neo4j·abp vnext
张鱼小丸子_微辣20 小时前
.Net Framework 4/C# LINQ*
c#