C# dataGridView 无法获取checkbox选中值

number007cool 2021-05-20 01:53:25
dataGridView 添加checkbox列,点击checkBox, 无法正确获取是否选中的状态


checkColumn = new DataGridViewCheckBoxColumn();
checkColumn.HeaderText = "select";
checkColumn.Name = "select";

dgv.Columns.Add(checkColumn);



Console.WriteLine(dgv.Columns.Count.ToString());



dgv.CellMouseClick += new DataGridViewCellMouseEventHandler((object sender, DataGridViewCellMouseEventArgs e) =>
{
if (e.ColumnIndex == 4)//列号为什么是4
{
//打印输出行号
Console.WriteLine("index " + e.RowIndex.ToString());

if (e.ColumnIndex == 4)
{
int i = e.RowIndex;

Boolean ret = Convert.ToBoolean(dgv1.Rows[i].Cells["select"].Selected);


if (ret)
Console.WriteLine("true");
else
Console.WriteLine("false");
}

}

});
...全文
23841 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
royler 2021-05-24
  • 打赏
  • 举报
回复
我大体猜测,代码啥的应该没什么问题,你单元格里面添加了checkbox ,无法获取选中,如果你的列是可编辑的,修改为当前列为只读,应该可以解决
luj_1768 2021-05-24
  • 打赏
  • 举报
回复
这么复杂啊,前面几位大神说的好像都是对的,不知问题解决了没有?是老代码在升级迭代中突然出问题了么?dataGridView是不能换的,界面响应代码也是不能改的,加上 .value也不行么?那么endEdit()呢?这两种方法可能都是正解。老代码维护是个艰难的项目,如果问题解决了,别忘了个大佬们结帖,即使是没采用的方案最好也给个回复。
number007cool 2021-05-24
  • 打赏
  • 举报
回复
引用 29 楼 爱喝茶的助手 的回复:
引用 28 楼 number007cool 的回复:
[quote=引用 27 楼 royler 的回复:]我大体猜测,代码啥的应该没什么问题,你单元格里面添加了checkbox ,无法获取选中,如果你的列是可编辑的,修改为当前列为只读,应该可以解决
修改为只读的话,check根本选不中
看下我的回复,改成只读,设定对应的选中和未选中的值,每次点击改变值就行了[/quote]已经可以了,多谢
爱喝茶的助手 2021-05-24
  • 打赏
  • 举报
回复
引用 28 楼 number007cool 的回复:
引用 27 楼 royler 的回复:
我大体猜测,代码啥的应该没什么问题,你单元格里面添加了checkbox ,无法获取选中,如果你的列是可编辑的,修改为当前列为只读,应该可以解决
修改为只读的话,check根本选不中
看下我的回复,改成只读,设定对应的选中和未选中的值,每次点击改变值就行了
number007cool 2021-05-24
  • 打赏
  • 举报
回复
引用 27 楼 royler 的回复:
我大体猜测,代码啥的应该没什么问题,你单元格里面添加了checkbox ,无法获取选中,如果你的列是可编辑的,修改为当前列为只读,应该可以解决
修改为只读的话,check根本选不中
hudi0719 2021-05-23
  • 打赏
  • 举报
回复
参考一下参考一下
爱喝茶的助手 2021-05-22
  • 打赏
  • 举报
回复
前提是得关掉编辑
爱喝茶的助手 2021-05-22
  • 打赏
  • 举报
回复
综合了下,不如直接在点击事件改变value的值,点快了也只会导致勾不上,不会导致值有问题。



private void Form52_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
DataColumn dc = new DataColumn();
dc.ColumnName = "aa";
dt.Columns.Add(dc);
DataRow dr = dt.NewRow();
dr["aa"] = "bb";
dt.Rows.Add(dr);
dataGridView1.DataSource = dt;
DataGridViewCheckBoxColumn dvck = new DataGridViewCheckBoxColumn();
dvck.Name = "ck";
dvck.HeaderText = "选择";
dvck.TrueValue = "1";
dvck.FalseValue = "0";
dataGridView1.Columns.Add(dvck);
}

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex<0)
{
return;
}
if (dataGridView1.Rows[e.RowIndex].Cells["ck"].Value ==null || dataGridView1.Rows[e.RowIndex].Cells["ck"].Value.ToString() == "0")
{
dataGridView1.Rows[e.RowIndex].Cells["ck"].Value = "1";
}
else
{
dataGridView1.Rows[e.RowIndex].Cells["ck"].Value = "0";
}
label1.Text = dataGridView1.Rows[e.RowIndex].Cells["ck"].Value.ToString();

}
wang_peng 2021-05-22
  • 打赏
  • 举报
回复
引用 23 楼 morliz子轩 的回复:
[quote=引用 20 楼 wang_peng 的回复:]EditedFormattedValue 这东西,楼主更蒙, 而且少用CellClick, CellClic几乎就是最底层的事件,一但业务复杂,很难控制, 那么多衍生出来的事件,为什么不用呢?
如果你来教学生,那学的人,第一感觉,什么该学什么不要学,都已经搞不清楚了。 首先,是要会各种事件的调用关系。适不适合用,完全是在经验中总结而来。 这个不妥,那个不适合。让学习中的新人如何下手?完全杞人忧天[/quote] 那最后你看看楼主会不会用你的方法解决问题.解决不了问题,一切都是空谈
wang_peng 2021-05-22
  • 打赏
  • 举报
回复
引用 18 楼 morliz子轩 的回复:
都在一直强调这个焦点位置,实际上它只需要能实现将EditedFormattedValue为true的行,获取出来,就可以去做后面逻辑上的处理。 如果说,是要处理实行行上的逻辑,那就需要考虑到当前选中行焦点上的问题。实时行信息的获取和修改,一般直接用CellClick事件 之前我也一直在困扰这个原因,实际上完全可以不用去深究这个东西。 只需要在处理的位置,先进行:Dgv.EndEdit();取消单元格的编辑状态,就不会在获取行信息时报错。
EditedFormattedValue 这东西,楼主更蒙, 而且少用CellClick, CellClic几乎就是最底层的事件,一但业务复杂,很难控制, 那么多衍生出来的事件,为什么不用呢?
wang_peng 2021-05-22
  • 打赏
  • 举报
回复
你的需求,用ListView吧,比DataGridView简单不少
morliz子轩 2021-05-22
  • 打赏
  • 举报
回复
引用 20 楼 wang_peng 的回复:
EditedFormattedValue 这东西,楼主更蒙, 而且少用CellClick, CellClic几乎就是最底层的事件,一但业务复杂,很难控制, 那么多衍生出来的事件,为什么不用呢?
如果你来教学生,那学的人,第一感觉,什么该学什么不要学,都已经搞不清楚了。 首先,是要会各种事件的调用关系。适不适合用,完全是在经验中总结而来。 这个不妥,那个不适合。让学习中的新人如何下手?完全杞人忧天
Bridge_go 2021-05-21
  • 打赏
  • 举报
回复
dgv的数据修改必须失去焦点时才生效,所以你点击checkbox时界面显示是勾上的,但是你焦点还在,所以值还是false
number007cool 2021-05-21
  • 打赏
  • 举报
回复
引用 15 楼 wang_peng 的回复:
[quote=引用 12 楼 number007cool 的回复:][quote=引用 11 楼 wang_peng 的回复:][quote=引用 8 楼 number007cool 的回复:][quote=引用 7 楼 wang_peng 的回复:]选中一行后,点Button,在 Buttun_Click里
DataGridViewRow row = this.dataGridView1.SelectedRows[0];
object value = row.Cells[0].Value;


我要做的操作实际上很简单,
30行,每一行有一个checkbox,对用要绘制的30条曲线。

但是实际应用中,只需要选中部分的曲线绘制即可,所以搞了这个东西,用来设定要绘制哪几条曲线。

也就是我只需要获取到30行,每一行的checkbox的选中状态即可。无他。
wang_peng 2021-05-21
  • 打赏
  • 举报
回复
引用 12 楼 number007cool 的回复:
[quote=引用 11 楼 wang_peng 的回复:][quote=引用 8 楼 number007cool 的回复:][quote=引用 7 楼 wang_peng 的回复:]选中一行后,点Button,在 Buttun_Click里 DataGridViewRow row = this.dataGridView1.SelectedRows[0]; object value = row.Cells[0].Value;
没太听懂你的意思,这是要规定用户习惯,每次必须选中行后,才能点击checkbox?分两步走? 另外,我发现上面的逻辑还有个问题,如果在同一行的的checkbox来回点击就没有任何反应。[/quote] 首先,选中行的方式有3种, 其中一种就是只要点了当前行的任何一个单元格,就算选中行 所以你可以直接点checkbox,也就相当于选中行了, 然后随便找个事件, 把我上面的代码放进去就可以了, 没返应可能是你代码有问题,仔细看一下吧.试着把所有的关于dataGridview的事件全屏蔽了, 看看还出不出问题[/quote] 我按照你上面的代码来。然后只开了一个事件,然后点击测试。发现有的时候是正确的,有的时候就是反的。 照理说这种控件很常规的操作,怎么会这么麻烦呢

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using HslCommunication;



namespace vs_UdpS
{
    public partial class Form_Config : Form
    {
        public Form_Config()
        {
            InitializeComponent();

            InitDgv(dgv1);
        }

        public void InitDgv(DataGridView dgv)
        {
            dgv.RowCount = 30;
            dgv.ColumnCount = 4;
            dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;//整行选中
            //dgv.CellDoubleClick += new DataGridViewCellEventHandler(dgvCellDoubleClick);

            dgv.Columns[0].Width = 200;

            int idx = 0;
            dgv.Rows[idx].Cells[2].Value = "";
            idx = idx + 1;
            dgv.Rows[idx].Cells[2].Value = "";
            idx = idx + 1;
            dgv.Rows[idx].Cells[2].Value = "";
            idx = idx + 1;
            dgv.Rows[idx].Cells[2].Value = "";
            idx = idx + 1;


            DataGridViewCheckBoxColumn checkColumn = new DataGridViewCheckBoxColumn();
            checkColumn.HeaderText = "select";
            checkColumn.Name = "select";

            dgv.Columns.Add(checkColumn);

            for (int i = 0; i < dgv.Rows.Count; i++ )
            {
                dgv.Rows[i].Cells[4].Value = true;
            }



             dgv.CellMouseClick += new DataGridViewCellMouseEventHandler(dgv_MouseClick);
        

            //dgv.MultiSelect = 
        }


        private void dgv_MouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.ColumnIndex == 4)
            {
                bool isChecked = bool.Parse(this.dgv1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
                lbShow.Text = isChecked.ToString();
                Console.WriteLine(isChecked.ToString());
                this.dgv1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !isChecked;
            }
        }

        private void Form_Config_Load(object sender, EventArgs e)
        {

        }
    }
}


[/quote] 1.如果你就这点代码,那你这代码没有什么问题,应该还是你操作的事 2.dgv_MouseClick 这个事件按你代码逻辑,没必要用,DataGridViewCheckBoxCell本身就点击的时候自己就可以变化, 3. dgv.RowCount = 30; dgv.ColumnCount = 4; 这什么要这样搞呢, 数据源上不要直接操作控件, 不了解原理的情况下,很麻烦, 要操作数据源, 通过数据源的变化, 在datagridview显示出来,就有点像mvvm的思想. 4.所以
 DataTable dt1 = new DataTable();
            dt1.TableName = "dt1";
            dt1.Columns.Add("select", typeof(Boolean));
            dt1.Columns.Add("Name");

            for (int i = 0; i < 100; i++)
            {
                DataRow dataRow = dt1.NewRow();
                dataRow[0] = true;
                dataRow[1] = i.ToString() + ".Name";
                dt1.Rows.Add(dataRow); 
            }


            DataGridViewTextBoxColumn columnName = new DataGridViewTextBoxColumn(); 
            columnName.HeaderText = "Name";
            columnName.DataPropertyName = "Name"; 
            this.dataGridView1.Columns.Add(columnName);

            DataGridViewCheckBoxColumn columnSelect = new DataGridViewCheckBoxColumn();
            columnSelect.HeaderText = "select";
            columnSelect.DataPropertyName = "select"; 
           
            this.dataGridView1.Columns.Add(columnSelect);
            this.dataGridView1.AutoGenerateColumns = false;
            this.dataGridView1.DataSource = dt1; 
这样,尽量操作DataTable,当然你也可以用其它替换DataTable.
morliz子轩 2021-05-21
  • 打赏
  • 举报
回复
都在一直强调这个焦点位置,实际上它只需要能实现将EditedFormattedValue为true的行,获取出来,就可以去做后面逻辑上的处理。 如果说,是要处理实行行上的逻辑,那就需要考虑到当前选中行焦点上的问题。实时行信息的获取和修改,一般直接用CellClick事件 之前我也一直在困扰这个原因,实际上完全可以不用去深究这个东西。 只需要在处理的位置,先进行:Dgv.EndEdit();取消单元格的编辑状态,就不会在获取行信息时报错。
morliz子轩 2021-05-21
  • 打赏
  • 举报
回复
另外,对CheckBox,有很多种写法,上面用的是foreach,获取DataGridViewCheckBoxCell对象,再转换成bool进行判断处理。 也可以写成for来做条件上的判断,demo:

for (int i = 0; i < DgvUser.Rows.Count; i++)
{
    if ((bool)DgvUser.Rows[i].Cells[0].EditedFormattedValue == true)
    {
        Info.Add((int)DgvUser.Rows[i].Cells["id"].Value);
        DgvUser.Rows.RemoveAt(DgvUser.Rows[i].Index);

        i--;
        //删除1行时,行索引会发生改变。比如删除5、6行,删除第5行时,第6行的索引会变成5
    }
    else
        continue;
}
实际上在学习Dgv的过程中,是先要搞清楚对象每种事件的触发特点,先后顺序。这样才能有助于你设计时,能快速调用效率较高的Dgv事件。
morliz子轩 2021-05-21
  • 打赏
  • 举报
回复
三个细节: 1、添加【多选】列: //插入多选[列]到首列位置

DataGridViewCheckBoxColumn multiselect = CreateCheckColumn("multiselect", "选择");
Dgv.Columns.Insert(0, multiselect);
//其中【CreateCheckColumn】方法:

         /// <summary>
        /// 创建基于DataGridView多选CheckBox控件
        /// </summary>
        /// <param name="ChkName">对象Name</param>
        /// <param name="HeaderCaption">对象HeaderText</param>
        /// <param name="DataFieldname">对象DataPropertyName</param>
        /// <returns></returns>
        public static DataGridViewCheckBoxColumn CreateCheckColumn(string ChkName, string HeaderCaption, string DataFieldname = null)
        {
            DataGridViewCheckBoxColumn column = new DataGridViewCheckBoxColumn()
            {
                Name = ChkName,
                HeaderText = HeaderCaption,
                DataPropertyName = DataFieldname,
                SortMode = DataGridViewColumnSortMode.NotSortable,
                TrueValue = false,
                ReadOnly = true,

                AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells,
                FlatStyle = FlatStyle.Standard,
                CellTemplate = new DataGridViewCheckBoxCell()
            };
            column.CellTemplate.Style.BackColor = Color.Beige;

            return column;
        }
2、实现在点击每行或单元格时,自动钩选CheckBox:(可以添加到Form_Load或自定义类构造函数来实现)

/// <summary>
/// 最后选中行号
/// </summary>
public int LastRowIndex { get; set; }

private void Form_Load(object sender, EventArgs e)
{
            //单元格单击事件
            Dgv.CellClick += new DataGridViewCellEventHandler(Dgv_CellClick);
}

        /// <summary>
        /// 单元格单击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Dgv_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView grid = sender as DataGridView;
            if (e.ColumnIndex == -1 || e.RowIndex == -1) return;
            LastRowIndex = e.RowIndex;

            if (e.ColumnIndex > 0)
            {
                //grid.ClearSelection();
                for (int i = 0; i < grid.Rows.Count; i++)
                {
                    DataGridViewCheckBoxCell cell = grid.Rows[i].Cells[0] as DataGridViewCheckBoxCell;
                    if (i == e.RowIndex)
                        cell.Value = true;
                    else
                        cell.Value = false;
                }

            }
        }
3、最后,就是在需要的位置,去实现判断CheckBox打钩的行逻辑上的处理,Demo:

Dgv.EndEdit();
foreach (DataGridViewRow row in DgvJob.Rows)
{
    DataGridViewCheckBoxCell checkBoxCell = row.Cells[0] as DataGridViewCheckBoxCell;
    bool CheckState = checkBoxCell.Value != null ? (bool)checkBoxCell.Value : false;

    if (CheckState)
    {
        //是否有重复添加
        //string select_Jobno = row.Cells["Jobna"].Value.ToString();
        string select_Jobna = row.Cells["Jobna"].EditedFormattedValue.ToString();

        DataRow[] dtRow = DgvHelper.dtBranchJob.Select("Jobna ='" + select_Jobna + "'");
        if (dtRow != null && dtRow.Length > 0)
        {
            if (MessageDxUtil.ShowYesNoAndError("职位名称【" + select_Jobna + "】已存在本部门中,不允许重复新增,是否自动删除此行?") == DialogResult.Yes)
            {
                Dgv.AllowUserToAddRows = false;  //禁止添加
                Dgv.Rows.Remove(row);
            }
            return;
        }

        BranJob BranJobObj = new BranJob()
        {
            Branno = DgvHelper.BranObj.Branno,
            Jobno = row.Cells["Jobna"].Value.ToString(),
            Planqty = (int)row.Cells["Planqty"].Value,
            Overtime = row.Cells["Overtime"].Value != DBNull.Value ? (decimal)row.Cells["Overtime"].Value : 0
        };

        AddObjInfo.Add(BranJobObj);
    }

}
number007cool 2021-05-20
  • 打赏
  • 举报
回复
引用 11 楼 wang_peng 的回复:
[quote=引用 8 楼 number007cool 的回复:][quote=引用 7 楼 wang_peng 的回复:]选中一行后,点Button,在 Buttun_Click里
DataGridViewRow row = this.dataGridView1.SelectedRows[0];
object value = row.Cells[0].Value;


没太听懂你的意思,这是要规定用户习惯,每次必须选中行后,才能点击checkbox?分两步走?



另外,我发现上面的逻辑还有个问题,如果在同一行的的checkbox来回点击就没有任何反应。[/quote]
首先,选中行的方式有3种, 其中一种就是只要点了当前行的任何一个单元格,就算选中行
所以你可以直接点checkbox,也就相当于选中行了,
然后随便找个事件,
把我上面的代码放进去就可以了,
没返应可能是你代码有问题,仔细看一下吧.试着把所有的关于dataGridview的事件全屏蔽了,
看看还出不出问题[/quote]

我按照你上面的代码来。然后只开了一个事件,然后点击测试。发现有的时候是正确的,有的时候就是反的。

照理说这种控件很常规的操作,怎么会这么麻烦呢

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using HslCommunication;



namespace vs_UdpS
{
public partial class Form_Config : Form
{
public Form_Config()
{
InitializeComponent();

InitDgv(dgv1);
}

public void InitDgv(DataGridView dgv)
{
dgv.RowCount = 30;
dgv.ColumnCount = 4;
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;//整行选中
//dgv.CellDoubleClick += new DataGridViewCellEventHandler(dgvCellDoubleClick);

dgv.Columns[0].Width = 200;

int idx = 0;
dgv.Rows[idx].Cells[2].Value = "";
idx = idx + 1;
dgv.Rows[idx].Cells[2].Value = "";
idx = idx + 1;
dgv.Rows[idx].Cells[2].Value = "";
idx = idx + 1;
dgv.Rows[idx].Cells[2].Value = "";
idx = idx + 1;


DataGridViewCheckBoxColumn checkColumn = new DataGridViewCheckBoxColumn();
checkColumn.HeaderText = "select";
checkColumn.Name = "select";

dgv.Columns.Add(checkColumn);

for (int i = 0; i < dgv.Rows.Count; i++ )
{
dgv.Rows[i].Cells[4].Value = true;
}



dgv.CellMouseClick += new DataGridViewCellMouseEventHandler(dgv_MouseClick);


//dgv.MultiSelect =
}


private void dgv_MouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == 4)
{
bool isChecked = bool.Parse(this.dgv1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString());
lbShow.Text = isChecked.ToString();
Console.WriteLine(isChecked.ToString());
this.dgv1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !isChecked;
}
}

private void Form_Config_Load(object sender, EventArgs e)
{

}
}
}




wang_peng 2021-05-20
  • 打赏
  • 举报
回复
引用 8 楼 number007cool 的回复:
[quote=引用 7 楼 wang_peng 的回复:]选中一行后,点Button,在 Buttun_Click里 DataGridViewRow row = this.dataGridView1.SelectedRows[0]; object value = row.Cells[0].Value;
没太听懂你的意思,这是要规定用户习惯,每次必须选中行后,才能点击checkbox?分两步走? 另外,我发现上面的逻辑还有个问题,如果在同一行的的checkbox来回点击就没有任何反应。[/quote] 首先,选中行的方式有3种, 其中一种就是只要点了当前行的任何一个单元格,就算选中行 所以你可以直接点checkbox,也就相当于选中行了, 然后随便找个事件, 把我上面的代码放进去就可以了, 没返应可能是你代码有问题,仔细看一下吧.试着把所有的关于dataGridview的事件全屏蔽了, 看看还出不出问题
加载更多回复(10)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧