【问题标题】:I need to allow user to check only one checkbox in all three columns checkboxes added in datagridview C#我需要允许用户在datagridview C#中添加的所有三列复选框中只选中一个复选框
【发布时间】:2020-09-25 11:41:09
【问题描述】:

我有一个从数据表加载的数据网格视图。 我通过 DataGridViewCheckBoxCell 类手动添加三列。 每行将根据用户选中的复选框进行更新。 我面临的问题是如何限制用户从加载的 datagridview 中所选行中的所有三个可用复选框中选择或选中一个复选框。

如果有在 datagridview 列中添加单选按钮的选项,或者我可以添加一组 3 个单选按钮作为每一行的列,问题将得到解决。

This is what my datagrid looks like after adding 3 datagridviewcheckboxCells

我的添加列的代码sn-p是

if (DG.DataSource != null)
                {
                    DataGridViewCheckBoxColumn ChbColReceived = new DataGridViewCheckBoxColumn();
                    DataGridViewCheckBoxColumn ChbColCancelled = new DataGridViewCheckBoxColumn();
                    DataGridViewCheckBoxColumn ChbColStop = new DataGridViewCheckBoxColumn();
                    DG.Columns.Add(ChbColReceived);
                    DG.Columns.Add(ChbColCancelled);
                    DG.Columns.Add(ChbColStop);
                    ChbColReceived.HeaderText = "Received";
                    ChbColCancelled.HeaderText = "Cancelled";
                    ChbColStop.HeaderText = "Stopped";
                }

您的建议将是可观的。 问候

解决方案: 感谢所有帮助我的开发者/大师。特别感谢@JohnG,他的回答也被勾选了。我已经对其进行了一些更改,这对于回答的人来说可能是可以接受的。这是我的代码解决了我的问题。

private void DG_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            try
            {
                int colIndex = DG.CurrentCell.ColumnIndex;
                int rowIndex = DG.CurrentCell.RowIndex;
                bool currentValue;
                if (DG.Columns[colIndex].Index == 11 || DG.Columns[colIndex].Index == 12 || DG.Columns[colIndex].Index == 13)
                {
                    DG.CurrentCellDirtyStateChanged -= new EventHandler(DG_CurrentCellDirtyStateChanged);
                    currentValue = !(bool)DG.Rows[rowIndex].Cells[colIndex].FormattedValue;
                    switch (DG.Columns[colIndex].Index)
                    {
                        case 11:
                            if (currentValue == true)
                            {
                                DG.Rows[rowIndex].Cells[12].Value = false;
                                DG.Rows[rowIndex].Cells[13].Value = false;
                            }
                            break;
                        case 12:
                            if (currentValue == true)
                            {
                                DG.Rows[rowIndex].Cells[11].Value = false;
                                DG.Rows[rowIndex].Cells[13].Value = false;
                            }
                            break;
                        case 13:
                            if (currentValue == true)
                            {
                                DG.Rows[rowIndex].Cells[11].Value = false;
                                DG.Rows[rowIndex].Cells[12].Value = false;
                            }
                            break;
                    }
                    DG.CommitEdit(DataGridViewDataErrorContexts.Commit);
                    DG.CurrentCellDirtyStateChanged += new EventHandler(DG_CurrentCellDirtyStateChanged);
                }
            }
            catch (Exception) { throw; }
        }

Col[11],Col[12],col[13] 是我的目标复选框列。 感谢@JohnG 的时间和关注。

【问题讨论】:

  • 您可以在项目模型中进行设置...基本上在设置器中,如果值为 true,则将其他 bool 值设置为 false ...绑定应该执行此操作(只要实现了 INotifyPropertyChanged
  • 你能自己改变数据表类吗?由于它是一个数据表,我假设您也将存储信息?通常我会使用枚举属性(单个字段)并将 3 个复选框列绑定到更新该单个字段的辅助属性。这样可以确保只有一个复选框为真
  • 得到不稳定的结果并不奇怪。 CurrentCellDirtyStateChanged 中发布的代码检查“EACH”复选框单元格,从 11 开始,然后 12 和 13。这将不起作用。您只想检查“已更改”复选框的值。其他“未更改”复选框无关紧要,因此没有必要选中它们。当您按照您的顺序更改它们时,就会发生这种情况……跟踪代码,您会看到……
  • 如果您启动应用程序,第一行的所有复选框都不会被选中。用户单击单元格 13 中的复选框。事件触发... 代码检查单元格 11 的值... 它不正确并被跳过,对于单元格 12 和 13 也是如此。记住,此事件触发“在”复选框更改之前.因此,第一次触发时,所有 if 条件都将返回 false。继续执行会退出事件并将单元格 13 中的复选框设置为 true。
  • 现在选中单元格 13,用户单击单元格 11 复选框。事件触发,由于尚未设置 11 中的复选框值,因此检查单元格 11 的第一个 if 语句将为 false。 12 处的单元格也将是错误的。但是,单元格 13 的当前状态为真,并将单元格 11 和 12 设置为假。然后执行离开事件 THEN 单元格 11 设置为真。在这里,您最终会同时检查单元格 11 和 13。

标签: c# datagridview


【解决方案1】:

有几种方法可以实现这一点,但是暴力方法是连接网格CurrentCellDirtyStateChanged 事件。此事件将在复选框更改其值之前触发,但是我们仍然可以使用它来确定复选框的当前状态。逻辑类似于……

检查更改的单元格是否是复选框单元格之一。如果是,则通过 NEGATING 它的当前值来检查它的值,例如......

currentValue = !(bool)dataGridView1.Rows[rowIndex].Cells[colIndex].FormattedValue;

注意“!”此处的否定作为它当前的任何值,当我们离开此事件时,它将变为否定值。从这里,我们只需检查新值是否为true,如果是,那么我们要将其他复选框设置为false。这可以通过一个简单的switch/case 语句来完成。

应该注意,由于代码可能会“更改”其他复选框的值,因此我们需要在设置这些值之前关闭此事件以避免任何类型的重入。

以下是上述内容的一个简单示例。我手动将列/行添加到网格中,但是,如果网格是数据绑定的,它应该仍然可以工作。

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) {
  int colIndex = dataGridView1.CurrentCell.ColumnIndex;
  int rowIndex = dataGridView1.CurrentCell.RowIndex;
  bool currentValue;
  string status = "Pending";
  if (dataGridView1.Columns[colIndex].Name == "Received" ||
      dataGridView1.Columns[colIndex].Name == "Canceled" ||
      dataGridView1.Columns[colIndex].Name == "Stopped") {
    dataGridView1.CurrentCellDirtyStateChanged -= new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
    currentValue = !(bool)dataGridView1.Rows[rowIndex].Cells[colIndex].FormattedValue;
    switch (dataGridView1.Columns[colIndex].Name) {
      case "Received":
        if (currentValue == true) {
          dataGridView1.Rows[rowIndex].Cells["Canceled"].Value = false;
          dataGridView1.Rows[rowIndex].Cells["Stopped"].Value = false;
          status = "Received";
        }
        break;
      case "Canceled":
        if (currentValue == true) {
          dataGridView1.Rows[rowIndex].Cells["Received"].Value = false;
          dataGridView1.Rows[rowIndex].Cells["Stopped"].Value = false;
          status = "Canceled";
        }
        break;
      case "Stopped":
        if (currentValue == true) {
          dataGridView1.Rows[rowIndex].Cells["Received"].Value = false;
          dataGridView1.Rows[rowIndex].Cells["Canceled"].Value = false;
          status = "Stopped";
        }
        break;
    }
    dataGridView1.Rows[rowIndex].Cells["CurrentStatus"].Value = status;
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    dataGridView1.CurrentCellDirtyStateChanged += new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
  }
}

【讨论】:

  • 亲爱的@JohnG:非常感谢您为帮助我所做的辛勤工作。事实上,我一直在想这件事。整个解决方案非常棒,但我从您的回答中得到的实际观点是 CurrentCellDirtyStateChanged 事件。我为此使用相同的事件计划了一个解决方案,如果它有效,我将分享它,你也会喜欢它。如果那不起作用,那么您的解决方案已经是最好的解决方案。我会更新我的问题并通知你。非常感谢。
  • 请检查我已编辑的问题并使用您的提示将解决方案放在那里。
【解决方案2】:

仅供参考,单选按钮默认执行此过程,我们使用单选按钮来选择性别。我们可以选择任何一个选项。您可以使用此默认过程来选择任何一列。使用复选框作为单选按钮。

check this stackoverflow solution

【讨论】:

  • 亲爱的杰瑞国王,正如我在图片中提到的那样,单选按钮解决方案将是一个更好的解决方案,但成本太高,而且还涉及大量的废话代码。我通过了解决方案,但这不符合我的要求。我需要一个单元格中的 3 个单选按钮,这变得很难管理。感谢您的关心。
猜你喜欢
  • 2016-05-22
  • 1970-01-01
  • 2012-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多