覆盖检查事件

时间:2013-07-30 15:13:06

标签: c# .net winforms

我有一个带复选框的DataGridView。复选框是自动抛出的,因为我的数据源有一个布尔“Selected”属性(如果这很重要)。

在这里用Google搜索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,以查看取消选中该框的内容是否会在那里处理,然后我可以撤消它。但显然这个过程直到事件处理程序方法完成后才会发生。

我该怎么做?

4 个答案:

答案 0 :(得分:1)

  

此处的用例是必须始终选择某些内容。

您需要处理数据网格视图的CellContentClick。然后,您可以检查是否有任何仍然选中的复选框。完成后,您可以根据您的使用案例致电CancelEditCommitEdit

答案 1 :(得分: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;
    }
}

答案 2 :(得分:0)

我的一位同事(Ben Zoski)建议完全删除复选框,只使用数据网格视图的自然点击选择来唯一标识一行:

enter image description here

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

我有点担心用户不会熟悉突出显示网格中某些行来选择某些内容的惯例(就像他们熟悉选中框一样),但是单一的复选框方法是复杂且不可靠(虽然我怀疑如果您希望用户能够选择多行,这是一种更好的方法。)

答案 3 :(得分: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;
    }
}

基本上代码正在做的是,通过跟踪用户在DataGridView中单击的最后一个CheckBox行索引,它将拒绝用户取消选中当前唯一的复选框,或者切换是否专门检查以前是否未选中的框。

处理CurrentCellDirtyStateChanged的原因是,默认情况下,DataGridView会在检查时将CheckBoxCell置于编辑模式。这将其作为对网格的更改提交。取消订阅然后重新订阅CellValueChanged事件的原因是为了防止在以编程方式更改函数本身内部的值时出现无限循环。

确保将索引字符串“CheckBoxColumn”更改为网格中的列。

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