Select 问卷样式 DataGridView 中的多个复选框列中只有一个复选框
Select only one checkbox from multiple checkbox columns in questionnaire style DataGridView
我创建了一个显示 DataGridView
和一系列问题的应用程序。
dgv 结构由一个用于问题文本的字符串列和三个用于答案的 bool/checkbox 列组成(是,否,N/A)。
每个问题都显示在自己的行中。
我希望我的程序只允许用户在每一行上仅 select 是,仅否或仅 N/A。
我想我需要在选中一个选项时取消选中其他复选框选项,但我不太确定如何执行此操作。
我已经设置了 CellValueChanged
和 CellContentClick
事件,但我不确定实现所需功能所需的代码。
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);
}
我希望这个示例有助于使 DataGridView 变得简单而强大;它与最初措辞 "Any help appreciated".
相关的 post
this video 是否显示了您正在寻找的行为?对我有用的是使用 BindingList 作为 DataGridView 的数据源。然后,使用复选框更改时发生的 'CellDirty' 事件,您可以使它们像单选按钮一样工作并回答您的问题:"select only one checkbox from multiple checkbox items"。
这里有一个 class 的例子,代表问卷中的一个项目。
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;
}
当您将此 class 绑定到 DataGridView 时,列将自动填充名为 'Question' 的列(这是只读的(因为 'set' 被标记为 internal) 和值 can 可以更改的三个复选框列(因为 get 和 设置 是 public)。
采用这种方法适用于 any class T 并且几乎完成了使用 DataGridView 的所有繁重工作。
以下是如何处理 CellDirty 事件,使三个复选框(我将它们命名为是、否和可能)像单选按钮一样工作:
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 具有其 window 句柄,绑定本身就很容易完成。为此,我们可以覆盖 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;
}
}
Clone or Download 这个例子来自 GitHub.
看来您 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) 个单元格。例如,如果“N/A”单元格最初被选中,然后用户“取消选中”该单元格,则该行将没有复选框被选中。这是代码中的最后检查,这样如果用户“取消选中”“N/A”单元格并且这会使所有复选框“未选中”,那么代码将“选中”“N/A” “ 细胞。此外,在我们更改 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);
}
下面是一个简单的示例,其中包含“是”、“否”和“N/A”三列复选框列。
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;
}
希望这对您有所帮助。
我创建了一个显示 DataGridView
和一系列问题的应用程序。
dgv 结构由一个用于问题文本的字符串列和三个用于答案的 bool/checkbox 列组成(是,否,N/A)。
每个问题都显示在自己的行中。
我希望我的程序只允许用户在每一行上仅 select 是,仅否或仅 N/A。
我想我需要在选中一个选项时取消选中其他复选框选项,但我不太确定如何执行此操作。
我已经设置了 CellValueChanged
和 CellContentClick
事件,但我不确定实现所需功能所需的代码。
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);
}
我希望这个示例有助于使 DataGridView 变得简单而强大;它与最初措辞 "Any help appreciated".
相关的 postthis video 是否显示了您正在寻找的行为?对我有用的是使用 BindingList 作为 DataGridView 的数据源。然后,使用复选框更改时发生的 'CellDirty' 事件,您可以使它们像单选按钮一样工作并回答您的问题:"select only one checkbox from multiple checkbox items"。
这里有一个 class 的例子,代表问卷中的一个项目。
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;
}
当您将此 class 绑定到 DataGridView 时,列将自动填充名为 'Question' 的列(这是只读的(因为 'set' 被标记为 internal) 和值 can 可以更改的三个复选框列(因为 get 和 设置 是 public)。 采用这种方法适用于 any class T 并且几乎完成了使用 DataGridView 的所有繁重工作。
以下是如何处理 CellDirty 事件,使三个复选框(我将它们命名为是、否和可能)像单选按钮一样工作:
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 具有其 window 句柄,绑定本身就很容易完成。为此,我们可以覆盖 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;
}
}
Clone or Download 这个例子来自 GitHub.
看来您 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) 个单元格。例如,如果“N/A”单元格最初被选中,然后用户“取消选中”该单元格,则该行将没有复选框被选中。这是代码中的最后检查,这样如果用户“取消选中”“N/A”单元格并且这会使所有复选框“未选中”,那么代码将“选中”“N/A” “ 细胞。此外,在我们更改 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);
}
下面是一个简单的示例,其中包含“是”、“否”和“N/A”三列复选框列。
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;
}
希望这对您有所帮助。