在问卷样式的DataGridView中,从多个复选框列中只选择一个复选框。

问题描述 投票:2回答:2

我创建了一个应用程序,它显示了一个 DataGridView dgv结构由一列字符串表示问题文本,三列boolcheckbox表示答案(yes, no, NA).每个问题都显示在自己的行中。

我希望我的程序只允许用户在每一行中只选择 "是"、"否 "或 "NA"。

我想当一个选项被选中时,我需要取消选中其他的复选框选项,但我不太清楚如何做到这一点。

我已经设置了 CellValueChangedCellContentClick 事件,但我不确定实现所需功能所需的代码。

DataGridView是绑定在DataTable上的。

到目前为止,我的代码。

private void dgvQuestions_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    int columnIndex = e.ColumnIndex;
    int rowIndex = e.RowIndex;

    DataGridViewCheckBoxCell chkYes = dgvQuestions.Rows[rowIndex].Cells[2] as DataGridViewCheckBoxCell;
    DataGridViewCheckBoxCell chkNo = dgvQuestions.Rows[rowIndex].Cells[3] as DataGridViewCheckBoxCell;
    DataGridViewCheckBoxCell chkNA = dgvQuestions.Rows[rowIndex].Cells[4] as DataGridViewCheckBoxCell;    

    if (Convert.ToBoolean(chkYes.Value) == true)
    {

    }

    if (Convert.ToBoolean(chkNo.Value) == true)
    {

    }

    if (Convert.ToBoolean(chkNA.Value) == true)
    {

    }
}

private void dgvQuestions_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    dgvQuestions.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
c# .net winforms datagridview datagridviewcolumn
2个回答
1
投票

看起来你有 CellContentClick 但是,如果在网格中还有其他列,那么,如果你检查一下,确保其内容被点击的单元格实际上是其中一个复选框单元格,可能会有好处。否则,代码可能会不必要地设置单元格的值。

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) {
  string colName = dataGridView1.Columns[e.ColumnIndex].Name;
  if (colName == "Yes" || colName == "No" || colName == "N/A") { 
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
  }
}

CellValueChanged 事件,同样代码应该只检查复选框的值。此外,我认为至少有一(1)个单元格必须被选中。例如,如果 "NA "单元格本来是被选中的,然后用户 "取消选中 "了该单元格,那么该行将没有选中的复选框。这是代码中的最后一项检查,如果用户 "取消选中""NA "单元格,并且所有的复选框都 "未选中",那么,代码将 "选中""NA "单元格。同时,"关闭 "以下选项也是很重要的。CellValueChanged 事件之前,我们改变任何一个复选框的值。CellValueChanged 事件,以避免重新进入。类似...

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
  if (e.RowIndex >= 0 && e.ColumnIndex >= 0) {
    string colName = dataGridView1.Columns[e.ColumnIndex].Name;
    bool checkValue;
    dataGridView1.CellValueChanged -= new DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged);
    switch (colName) {
      case "Yes":
        checkValue = (bool)dataGridView1.Rows[e.RowIndex].Cells["Yes"].Value;
        if (checkValue == true) {
          dataGridView1.Rows[e.RowIndex].Cells["No"].Value = false;
          dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value = false;
        }
        else {
          dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value = true;
        }
        break;
      case "No":
        checkValue = (bool)dataGridView1.Rows[e.RowIndex].Cells["No"].Value;
        if (checkValue == true) {
          dataGridView1.Rows[e.RowIndex].Cells["Yes"].Value = false;
          dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value = false;
        }
        else {
          dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value = true;
        }
        break;
      case "N/A":
        checkValue = (bool)dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value;
        if (checkValue == true) {
          dataGridView1.Rows[e.RowIndex].Cells["Yes"].Value = false;
          dataGridView1.Rows[e.RowIndex].Cells["No"].Value = false;
        }
        else {
          if ((bool)dataGridView1.Rows[e.RowIndex].Cells["Yes"].Value == false &&
              (bool)dataGridView1.Rows[e.RowIndex].Cells["No"].Value == false) {
            dataGridView1.Rows[e.RowIndex].Cells["N/A"].Value = true;
          }
        }
        break;
      default:
        break;
    }
    dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged);
  }

下面是一个简单的例子,有 "是"、"否"、"NA "三栏复选框栏。

public Form1() {
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e) {
  dataGridView1.DataSource = GetTable();
}

private DataTable GetTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("Yes", typeof(bool));
  dt.Columns.Add("No", typeof(bool));
  dt.Columns.Add("N/A", typeof(bool));
  for (int i = 0; i < 10; i++) {
    dt.Rows.Add(false, false, true);
  }
  return dt;
}

希望对大家有所帮助。


2
投票

我希望这个例子对使DataGridView变得简单而强大有帮助;它与原帖的措辞有关,原帖的措辞是 "感谢任何帮助"。

是否 本视频 显示出你正在寻找的行为?对我来说,有效的方法是使用BindingList作为DataGridView的数据源。然后,使用当一个复选框改变时发生的'CellDirty'事件,你可以让它们像一个热的单选按钮一样,并回答你的问题。"从多个复选框项目中只选择一个复选框"。

下面是一个代表问题单行项的类的例子。

class QuestionaireItem
{
    public string Question { get; internal set; } = "Question " + _count++;
    public bool Yes { get; set; }
    public bool No { get; set; }
    public bool Maybe { get; set; } // OOPS! I should have said "NA"

    static int _count = 1;
}

当你把这个类绑定到DataGridView上时,列会自动填充一个名为 "问题 "的列(它是只读的(因为 "集 "被标记为 内部)和三个复选框列,其值 可以 变化(因为两个 得到设置 是公开的)。) 采取这种方法对 任何 阶层 T 并几乎完成了使用DataGridView的所有繁重工作。

下面是如何处理CellDirty事件,使三个复选框(我把它们命名为Yes、No和Maybe)像单选按钮一样。

private void DataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    // The cell will be considered "dirty" or modified so Commit first.
    dataGridView1.EndEdit(DataGridViewDataErrorContexts.Commit);
    // Get the QuestionaireItem that is bound to the row
    QuestionaireItem item = (QuestionaireItem)
        dataGridView1
        .Rows[dataGridView1.CurrentCell.RowIndex]
        .DataBoundItem;
    // Now see which column changed:
    switch (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name)
    {
        case "Yes":
            item.No = false;        // i.e. "unchecked"
            item.Maybe = false;
            break;
        case "No":
            item.Yes = false;       
            item.Maybe = false;
            break;
        case "Maybe":
            item.Yes = false;
            item.No = false;
            break;
    }
    dataGridView1.Refresh();    // Update the binding list to the display
}

一旦MainForm有了窗口Handle,绑定本身就很简单。我们可以覆盖OnHandleCreated来实现这个目的。这里,绑定过程将正常工作,我们还可以设置列的显示宽度。这里展示了如何初始化 dataGridView1. 我已经放了注释来解释发生了什么。

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    if (!DesignMode)    // We only want this behavior at runtime
    {
        // Create the binding list
        BindingList<QuestionaireItem> testdata = new BindingList<QuestionaireItem>();
        // And add 5 example items to it
        for (int i = 0; i < 5; i++) testdata.Add(new QuestionaireItem());
        // Now make this list the DataSource of the DGV.
        dataGridView1.DataSource = testdata;

        // This just formats the column widths a little bit
        dataGridView1.Columns["Question"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
        dataGridView1.Columns["Maybe"].Width =
        dataGridView1.Columns["Yes"].Width =
        dataGridView1.Columns["No"].Width = 40;

        // And this subscribes to the event (one of them anyway...)
        // that will fire when the checkbox is changed
        dataGridView1.CurrentCellDirtyStateChanged += DataGridView1_CurrentCellDirtyStateChanged;
    }
}

克隆或下载 这个例子来自GitHub。

© www.soinside.com 2019 - 2024. All rights reserved.