【问题标题】:DataGridView CheckBox eventsDataGridView 复选框事件
【发布时间】:2010-05-21 20:37:11
【问题描述】:

我正在制作一个DataGridView,其中包含一系列复选框,水平和垂直方向具有相同的标签。任何相同的标签,复选框都将处于非活动状态,我只希望每个组合的两个“检查”之一有效。以下屏幕截图显示了我所拥有的:

任何在下半部分被选中的东西,我都希望在上半部分不被选中。因此,如果选中 [quux, spam](或 [7, 8] 用于从零开始的坐标),我希望 [spam, quux] ([8, 7]) 未选中。到目前为止,我有以下内容:

    dgvSysGrid.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
    dgvSysGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    string[] allsysNames = { "heya", "there", "lots", "of", "names", "foo", "bar", "quux", "spam", "eggs", "bacon" };

    // Add a column for each entry, and a row for each entry, and mark the "diagonals" as readonly
    for (int i = 0; i < allsysNames.Length; i++)
    {
        dgvSysGrid.Columns.Add(new DataGridViewCheckBoxColumn(false));
        dgvSysGrid.Columns[i].HeaderText = allsysNames[i];
        dgvSysGrid.Rows.Add();
        dgvSysGrid.Rows[i].HeaderCell.Value = allsysNames[i];
        // Mark all of the "diagonals" as unable to change
        DataGridViewCell curDiagonal = dgvSysGrid[i, i];
        curDiagonal.ReadOnly = true;
        curDiagonal.Style.BackColor = Color.Black;
        curDiagonal.Style.ForeColor = Color.Black;
    }

    // Hook up the event handler so that we can change the "corresponding" checkboxes as needed
    //dgvSysGrid.CurrentCellDirtyStateChanged += new EventHandler(dgvSysGrid_CurrentCellDirtyStateChanged);
    dgvSysGrid.CellValueChanged += new DataGridViewCellEventHandler(dgvSysGrid_CellValueChanged);

}

void dgvSysGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    Point cur = new Point(e.ColumnIndex, e.RowIndex);

    // Change the diagonal checkbox to the opposite state
    DataGridViewCheckBoxCell curCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.X, cur.Y];
    DataGridViewCheckBoxCell diagCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.Y, cur.X];
    if ((bool)(curCell.Value) == true)
    {
        diagCell.Value = false;
    }
    else
    {
        diagCell.Value = true;
    }
}

/// <summary>
/// Change the corresponding checkbox to the opposite state of the current one
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void dgvSysGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    Point cur = dgvSysGrid.CurrentCellAddress;

    // Change the diagonal checkbox to the opposite state
    DataGridViewCheckBoxCell curCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.X, cur.Y];
    DataGridViewCheckBoxCell diagCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.Y, cur.X];
    if ((bool)(curCell.Value) == true)
    {
        diagCell.Value = false;
    }
    else
    {
        diagCell.Value = true;
    }
} 

问题来了,如果我使用CellValueChanged 事件,更改的单元格值似乎总是“落后”,您实际单击的位置,如果我在其中,我不确定如何获取当前单元格curCell 的“脏”状态以 null 形式出现(暗示当前单元格地址在某种程度上是错误的,但我没有尝试获取该值)意味着该路径根本不起作用。

基本上,我如何获得具有正确布尔值的“正确”地址,以便我的翻转算法能够工作?

【问题讨论】:

    标签: c# .net datagridview checkbox


    【解决方案1】:

    最终,是 CurrentCellDirtyStateChanged 事件做到了,但您需要以正确的方式做到这一点。而正确的方式是MSDN的,虽然乍一看并没有什么意义。

    上面的一个片段,我最终做的是下面:

        // Hook up the event handler so that we can change the "corresponding" checkboxes as needed
        dgvSysGrid.CurrentCellDirtyStateChanged += new EventHandler(dgvSysGrid_CurrentCellDirtyStateChanged);
        dgvSysGrid.CellValueChanged += new DataGridViewCellEventHandler(dgvSysGrid_CellValueChanged);
    
    }
    
    void dgvSysGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        Point cur = new Point(e.ColumnIndex, e.RowIndex);
    
        // Change the diagonal checkbox to the opposite state
        DataGridViewCheckBoxCell curCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.X, cur.Y];
        DataGridViewCheckBoxCell diagCell = (DataGridViewCheckBoxCell)dgvSysGrid[cur.Y, cur.X];
        if ((bool)(curCell.Value) == true)
        {
            diagCell.Value = false;
        }
        else
        {
            diagCell.Value = true;
        }
    }
    
    void dgvSysGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        if (dgvSysGrid.IsCurrentCellDirty)
        {
            dgvSysGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }
    

    基本上,所有发生的事情都是CurrentCellDirtyStateChanged 事件触发CellValueChanged 事件,仅此而已。如果您只是附加CellValueChanged 事件,那么它只会在您离开单元格后触发。我不知道为什么(考虑到它是一个复选框,它不是立即“完成”吗?),但这就是发生的事情。并且上面的代码有效,因为单击它时复选框的更改会立即消失。所以它起作用了。

    【讨论】:

    • 是的! ...我的搜索结束了...我现在可以从此过上幸福的生活。谢谢。
    【解决方案2】:

    您可以使用CellValidating 事件,e.FormattedValue 将具有更改的值。如果您执行一些检查,并且不想更新值,请将 e.Cancel 设置为 true。

    这是来自 FormattedValue 页面的示例:

    private void dataGridView1_CellValidating(object sender,
        DataGridViewCellValidatingEventArgs e)
    {
        dataGridView1.Rows[e.RowIndex].ErrorText = "";
        int newInteger;
    
        // Don't try to validate the 'new row' until finished 
        // editing since there
        // is not any point in validating its initial value.
        if (dataGridView1.Rows[e.RowIndex].IsNewRow) { return; }
        if (!int.TryParse(e.FormattedValue.ToString(),
            out newInteger) || newInteger < 0)
        {
            e.Cancel = true;
            dataGridView1.Rows[e.RowIndex].ErrorText = "the value must be a non-negative integer";
        }
    }
    

    【讨论】:

    • 不幸的是,这不起作用,因为 CellValidating 事件仅在我离开单元格时触发,而不是在单击复选框和状态切换时触发。
    【解决方案3】:

    我发现的最简单的技术是:

    • 注册 grid_CellContentClick
    • 使用以下命令检查单元格的所有行,或仅检查事件处理程序中的行。我的代码需要从被点击单元格的整个状态重新创建一个数据模型。

    EditedFormattedValue 是单元格的“新”值,也是要读取的值。

    var colNumber=0;
    foreach (var row in grid.Rows) {
       var dataGridViewCell = (DataGridViewCheckBoxCell)((DataGridViewRow)(row)).Cells[colNumber];
       if (dataGridViewCell.EditedFormattedValue) {
            // This cell is now checked - do whatever you need to with the other cells
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-20
      • 1970-01-01
      • 2010-10-30
      • 2011-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多