1

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

在此处搜索论坛,我已经能够实现一种可以正常工作的互斥机制。

//  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

4 回答 4

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;
    }
}
于 2013-07-30T16:10:48.843 回答
1

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

你需要处理CellContentClickdatagridview。然后您可以检查是否有任何复选框仍处于选中状态。之后,您可以调用CancelEditCommitEdit根据您的用例。

于 2013-07-30T15:28:05.610 回答
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”更改为网格中的列。

不是最优雅的代码,但它相当简短和甜蜜。如果您决定走那条路,希望它对您有用。

于 2013-07-31T16:43:23.260 回答
0

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

在此处输入图像描述

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

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

于 2013-07-31T13:40:19.300 回答