none
DataGridView同时编辑CheckBox列中的多行数据 RRS feed

  • 问题

  • 在DataGridView中添加CheckBox列

    选中多行数据,勾选其中的某一个CheckBox

    想要实现的效果是,被选中的多行的CheckBox,变得和刚才勾选的那个CheckBox的值一致

    现在能够实现的是,类型是typeof(stirng)或typeof(int)的列,能够在CellValueChanged事件中,

    通过获得SelectedCells集合,来对选中的复数行cells的值,进行编辑

    问题在于,当列的类型是TypeOf(bool)的时候‘,CellValueChanged事件中,获得的SelectedCells,不再是之前的多行数据,变成了当前的cell

    以下是代码:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                InitializeUI();
            }
            DataTable dt;
            DataGridView gv;
            void InitializeUI()
            {
                dt = new DataTable();
                dt.Columns.Add("check",typeof(bool));
                dt.Columns.Add("Id", typeof(string));
                dt.Columns.Add("Amount", typeof(int));
                dt.Rows.Add(new object[] { false,1, 10 });
                dt.Rows.Add(new object[] { false,2, 9 });
                dt.Rows.Add(new object[] { false,3, 12 });
                dt.Rows.Add(new object[] { true,4, 3 });
                dt.Rows.Add(new object[] { false,5, 12 });
                gv = new DataGridView();
                gv.Dock = DockStyle.Fill;
                gv.MultiSelect = true;
                gv.DataSource = dt;
                gv.CellValueChanged += new DataGridViewCellEventHandler(gv_CellValueChanged);
                this.Controls.Add(gv);
            }
            void gv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
            {
                var cell = gv[e.ColumnIndex, e.RowIndex];
                foreach (DataGridViewCell item in gv.SelectedCells)
                {
                    if (cell.ColumnIndex != item.ColumnIndex)
                        continue;
                    if (cell == item)
                        continue;
                    item.Value = cell.Value;
                }
            }
        }

    2012年8月21日 15:28

答案

  • 在你这样进行绑定的时候,实际上column的产生并加入到column collection中是发生在control的生成过程中,而这个过程是在Form的构造函数之后调用的,所以建议你将column的访问放到Form.Load时间处理方法或其之后的执行方法中。

    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us

    2012年8月24日 5:47
    版主

全部回复

  • 原来按住Ctrl键,就可以同时编辑选中的CheckBox。

    但还是有疑问,按住Ctrl编辑别的列,DataGridView.SelectCells是除了当前cell的 其它背景变成蓝色的cells

    而按住Ctrl编辑CheckBox列,DataGridView.SelectCells是当前cell

    
    
    
    
    
    
    
    
    
    2012年8月22日 12:19
  • 

    追加疑问

    我直接在InitinalUI()方法中,追加一行代码,以启动CheckBox列的自动排序

    gv.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic;

    编译的时候提示Index超出范围,看了一下,是gv.Columns没有数据

    我已经把DataTable赋给了gv了,为什么Columns里面还没有数据呢

    于是我只好注册了一个事件

    gv.ColumnHeaderMouseClick+=new DataGridViewCellMouseEventHandler(gv_ColumnHeaderMouseClick);

    并增加了相应的方法

            void gv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
            {
                gv.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic;
            }

    这下问题又来了

    程序启动后,当我第一次点击CheckBox列的Header的时候,排序的三角图标没有出现,第二次点击Header的时候,

    才出现排序的三角图标,这又是为什么呢

    另外学文科的转行做程序员真的很苦逼,逻辑思维跟不上,智商是硬伤。。。。

    2012年8月22日 17:22
  • 于是我勉强接受了,需要点两次才能点亮排序那个三角图标的设定,接着往下走修改gv_CellValueChanged方法

    在本方法的开头去掉CellValueChanged事件集合指向本方法的连接(连接这个词形容的合适吗。。跪。。)

    因为我发现gv_CellValueChanged会被多调用选中行-1次,减一是因为要去掉Currentcell,因为你选择了几个cell,他们的值只要一修改,就会调用本方法

    在方法的结尾再把本方法关联到CellValueChanged事件上,于是为了方便,再发下修改后的代码

        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                InitializeUI();
            }
    
            DataTable dt;
            DataGridView gv;
    
            void InitializeUI()
            {
                dt = new DataTable();
                dt.Columns.Add("check", typeof(bool));
                dt.Columns.Add("Id", typeof(string));
                dt.Columns.Add("Amount", typeof(string));
    
                DataRow dtRow;
                for (int i = 0; i < 8; i++)
                {
                    dtRow = dt.NewRow();
                    dtRow["check"] = false;
                    dtRow["Id"] = i;
                    dtRow["Amount"] = "Amount" + i.ToString();
                    dt.Rows.Add(dtRow);
                }
    
                gv = new DataGridView();
                gv.Dock = DockStyle.Fill;
                gv.MultiSelect = true;
                gv.DataSource = dt;        
                gv.ColumnHeaderMouseClick+=new DataGridViewCellMouseEventHandler(gv_ColumnHeaderMouseClick);
                gv.CellValueChanged += new DataGridViewCellEventHandler(gv_CellValueChanged);            
                this.Controls.Add(gv);
    
            }
    
            void gv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
            {
                //增加排序,这里为什么要点击两次Header才能点亮排序的小三角图标
                gv.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic;
            }
            void gv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
            {
                //去掉委托,等待所有cell的值被修改完
                gv.CellValueChanged -= gv_CellValueChanged;
                var cell = gv[e.ColumnIndex, e.RowIndex];
    
                //这里的gv.SelectedCells,为什么在其他列中选择了复数行之后,修改cell的值,
                //取到的是除了当前cell的其他cells的集合
                //而在CheckBox列中,选择复数行,点击checkBox后,gv.SelectedCells取到的仅仅是当前cell
                //在不按住ctrl的前提下
                foreach (DataGridViewCell item in gv.SelectedCells)
                {
    
                    if (cell.ColumnIndex != item.ColumnIndex)
                        continue;
    
                    if (cell == item)
                        continue;
    
                    item.Value = cell.Value;
                }
    
                //重新关联委托
                gv.CellValueChanged += gv_CellValueChanged;
            }
        }
    现在的结果是,除了编辑的那个cell,其他被选中的cell,正确排序了
    这个要怎么解
    2012年8月22日 17:54
  • 

    追加疑问

    我直接在InitinalUI()方法中,追加一行代码,以启动CheckBox列的自动排序

    gv.Columns[0].SortMode = DataGridViewColumnSortMode.Automatic;

    编译的时候提示Index超出范围,看了一下,是gv.Columns没有数据

    我已经把DataTable赋给了gv了,为什么Columns里面还没有数据呢

    这个疑问解决了,需要先把DataGridView加入到From.Controls中,只是知其然不知其所以然
    2012年8月23日 12:21
  • 在你这样进行绑定的时候,实际上column的产生并加入到column collection中是发生在control的生成过程中,而这个过程是在Form的构造函数之后调用的,所以建议你将column的访问放到Form.Load时间处理方法或其之后的执行方法中。

    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us

    2012年8月24日 5:47
    版主