2013-07-30 89 views
1

我有一个DataGridView复选框。复选框被自动引入,因为我的数据源有一个布尔型“Selected”属性(如果有的话)。覆盖检查事件

使用谷歌搜索forums在这里我已经能够实现一个互相排斥机制的工作好。

// unselect all the other ones 
foreach (DataGridViewRow dgvr in dataGridView1.Rows) 
{ 
    ((DataGridViewCheckBoxCell)dgvr.Cells[e.ColumnIndex]).Value = false; 
} 
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = true; 

问题是如果用户单击一个复选框,该框取消选中。这里的用例是必须始终选择一些东西。

我的第一种方法是确保现有列索引的值设置为true。它是。但问题仍然存在......

我的第二种方法是将DataGridViewCellEventArgs的处理事件设置为true,以阻止任何下游事件干扰我们的特定用例条件。显然这个类没有处理过的属性(它的基类也没有)。

我的第三种方法是调用Application.DoEvents()一万次,然后将Value设置为true以查看是否取消选中该框将在该处处理,然后我可以撤消它。但显然这个过程直到事件处理程序方法完成之后才会发生。

我该怎么做?

+0

你的问题我也不清楚。我没有得到你想要的datagridview,你想做一些类似你发布的代码,但你不想使用'foreach'或者任何'loop'? –

+0

@KingKing:嗯,我想我需要那个。问题是,有些如何似乎有一些其他过程,不检查我在那里检查了什么。 – micahhoover

回答

1

这里的用例是必须始终选择某个东西。

您需要处理datagridview的CellContentClick。然后你可以检查是否有任何复选框仍然被选中。完成之后,您可以根据您的使用情况调用CancelEditCommitEdit

+0

这使我得到了一些方法(所以+1)。不幸的是,双击事件似乎可以解决这个问题。我尝试创建一个虚拟的双击方法,并将两个事件引导到相同的方法,但都不起作用。 – micahhoover

+0

你能分享你的更新代码吗? – Ehsan

1

这可能会帮助:

// A list of the check box cell so we can use LINQ to access them 
private List<DataGridViewCheckBoxCell> checkBoxCellList = new List<DataGridViewCheckBoxCell>(); 

private DataGridView dgv = new DataGridView(); 

private void dataGridViewBuild() { 
    DataGridViewCheckBoxColumn cbcolumn = new DataGridViewCheckBoxColumn(false); 
    cbcolumn.Name = "Selected"; 
    cbcolumn.HeaderText = cbcolumn.Name;    
    this.dgv.Columns.Add(cbcolumn); 

    // Add 100 rows 
    for (int i = 0; i < 100; i++) { 
     dgv.Rows.Add(); 
    } 

    // Get all of the checkbox cells and add them to the list 
    foreach (DataGridViewRow row in this.dgv.Rows) {     
     this.checkBoxCellList.Add((DataGridViewCheckBoxCell)row.Cells["Selected"]); 
    }    

    // Subscribe to the value changed event for the datagridview 
    this.dgv.CellValueChanged += new DataGridViewCellEventHandler(dgv_CellValueChanged);    

    this.Controls.Add(this.dgv); 
} 

void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e) { 

    // Get the cell checkbox cell for the row that was changed 
    DataGridViewCheckBoxCell checkBoxCell = (DataGridViewCheckBoxCell)this.dgv[e.ColumnIndex, e.RowIndex]; 

    // If the value is true then set all other checkboxcell values to false with LINQ 
    if (checkBoxCell.Value != null && Convert.ToBoolean(checkBoxCell.Value)) { 
     this.checkBoxCellList.FindAll(cb => Convert.ToBoolean(cb.Value) == true && cb != checkBoxCell).ForEach(cb => cb.Value = false); 
    } 

    // If the checkboxcell was made false and no other is true then reset the value to true  
    if (this.checkBoxCellList.FindAll(cb => Convert.ToBoolean(cb.Value) == true).Count == 0) { 
      checkBoxCell.Value = true; 
    } 
} 
+0

检查并取消选中复选框单元格时,“CellValueChanged”甚至没有被触发?我已经测试过这个事件,这有点奇怪,也许只适用于checkboxcell。 –

+0

将数据保存到datagridview时触发。点击复选框,然后点击另一行,它应该会触发。 – jiverson

+0

@jiverson:我有和KingKing一样的经历。我没有看到该事件被可靠地解雇。 +1将我介绍给foreach lambda方法。最后我检查了它不在101 linq教程中。 – micahhoover

0

我的一个同事(本Zoski)建议干脆,只是去掉复选框使用数据网格视图的自然点击选择唯一标识行:

enter image description here

为此,我将数据网格视图的SelectionMode属性设置为:“FullRowSelect”。

我有点担心用户不会熟悉突出显示网格中的特定行以选择某些内容(与熟悉检查框的方式相同),但单个复选框方法是复杂和不可靠的(尽管我怀疑如果你希望用户能够选择多行,这是一个更好的方法)。

0

看起来像你通过改变方向来回答自己的问题,但我想我会抛出一个可能的解决方案,以防止你想要坚持使用CheckBoxes。考虑以下代码:

private static int _previousClickedCheckBoxRowIndex; 

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
{ 
    var dgv = (DataGridView)sender; 

    if ((dgv.IsCurrentCellDirty) & (dgv.CurrentCell.OwningColumn == dgv.Columns["CheckBoxColumn"])) 
    { 
     dgv.CommitEdit(DataGridViewDataErrorContexts.Commit); 
    } 
} 

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    var dgv = (DataGridView)sender; 

    if (dgv.Columns[e.ColumnIndex] == dgv.Columns["CheckBoxColumn"]) 
    { 
     dgv.CellValueChanged -= dataGridView1_CellValueChanged; 

     if (_previousClickedCheckBoxRowIndex == e.RowIndex) 
     { 
      dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = 
       !((bool)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value); 

      dgv.RefreshEdit(); 

     } 
     else 
     { 
      dgv.Rows[_previousClickedCheckBoxRowIndex].Cells["CheckBoxColumn"].Value = false; 
      _previousClickedCheckBoxRowIndex = e.RowIndex;        
     } 

     dgv.CellValueChanged += dataGridView1_CellValueChanged; 
    } 
} 

基本上什么代码正在做的是,通过保持最后的CheckBox行索引的用户在你的DataGridView点击的轨道,它会要么拒绝来自未检查只检查当前用户框,或者将该框切换为独立检查,如果它以前未被选中。

处理CurrentCellDirtyStateChanged的原因是,默认情况下,DataGridView在编辑模式下离开CheckBoxCell。这将它作为对网格的更改提交。取消订阅然后重新订阅CellValueChanged事件的原因是为了防止在程序中更改函数内部的值时出现无限循环。

确保您更改索引字符串“CheckBoxColumn”到列在您的网格。

不是最优雅的代码,但它是相当简短而亲切。如果你决定走这条路,希望它对你有用。