C# CellValueChanged期间winform datagridview更新值
我正在构建这样一个应用程序: 在表中的每一行中:C# CellValueChanged期间winform datagridview更新值,c#,winforms,datagridview,C#,Winforms,Datagridview,我正在构建这样一个应用程序: 在表中的每一行中: 用户可以在选项1和选项2列中选中或取消选中值。 之后,All option列中复选框的值将更新为: -“选中”:如果选中了选项1和选项2, -“未选中”:如果选项1和选项2都未选中 -“不确定”:其他情况 用户可以选中或取消选中所有选项列中的值。 之后,选项1和选项2的值将根据所有选项的当前值更新 在这种情况下,用户无法将All option列的值更改为不确定(仅在选中和未选中之间切换) 我正在Winforms中使用DataGridVi
- 用户可以在
和选项1
列中选中或取消选中值。选项2
之后,
列中复选框的值将更新为:All option
-“选中”:如果选中了
和选项1
,选项2
-“未选中”:如果
和选项1
都未选中选项2
-“不确定”:其他情况
- 用户可以选中或取消选中
列中的值。所有选项
之后,
和选项1
的值将根据选项2
所有选项的当前值更新
在这种情况下,用户无法将
列的值更改为不确定(仅在选中和未选中之间切换)All option
public partial class Form1 : Form
{
DataTable dataTable;
public Form1()
{
InitializeComponent();
dataTable = new DataTable();
dataTable.Columns.Add("Item");
dataTable.Columns.Add("All option", typeof(CheckState));
dataTable.Columns.Add("Option 1", typeof(bool));
dataTable.Columns.Add("Option 2", typeof(bool));
dataTable.Rows.Add("Item 1", CheckState.Unchecked, false, false);
dataTable.Rows.Add("Item 2", CheckState.Unchecked, false, false);
dataGrid.DataSource = dataTable;
}
private void dataGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGrid.CurrentCell is DataGridViewCheckBoxCell)
{
dataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
bool isUnderUpdateAll = false;
private void dataGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if ((dataGrid.CurrentCell is DataGridViewCheckBoxCell) == false) return;
// This is column "All option"
if (e.ColumnIndex == 1)
{
// Avoid stackoverflow exception
if (isUnderUpdateAll) return;
CheckState allOption = (CheckState)dataGrid["All option", e.RowIndex].Value;
// Don't allow user select 'indeterminate' value
if (allOption == CheckState.Indeterminate)
{
allOption = CheckState.Unchecked;
// These code didn't work
dataTable.Rows[e.RowIndex]["All option"] = CheckState.Unchecked;
dataGrid["All option", e.RowIndex].Value = CheckState.Unchecked;
dataGrid.UpdateCellValue(e.ColumnIndex, e.RowIndex);
dataGrid.NotifyCurrentCellDirty(true);
dataGrid.Refresh();
dataGrid.Update();
}
dataGrid["Option 1", e.RowIndex].Value = allOption;
dataGrid["Option 2", e.RowIndex].Value = allOption;
}
// This is column "Option 1" or "Option 2"
else
{
bool option1 = (bool)dataGrid["Option 1", e.RowIndex].Value;
bool option2 = (bool)dataGrid["Option 2", e.RowIndex].Value;
isUnderUpdateAll = true;
dataGrid["All option", e.RowIndex].Value = (option1 && option2) ? CheckState.Checked
: (!option1 && !option2 ? CheckState.Unchecked : CheckState.Indeterminate );
isUnderUpdateAll = false;
}
}
}
代码似乎有效,但有一点不完整:用户仍然可以在All选项
列中切换到不确定状态。在我的代码中,我已经添加了许多内容,如:
// Don't allow user select 'indeterminate' value
if (allOption == CheckState.Indeterminate)
{
allOption = CheckState.Unchecked;
// These code didn't work
dataTable.Rows[e.RowIndex]["All option"] = CheckState.Unchecked;
dataGrid["All option", e.RowIndex].Value = CheckState.Unchecked;
dataGrid.UpdateCellValue(e.ColumnIndex, e.RowIndex);
dataGrid.NotifyCurrentCellDirty(true);
dataGrid.Refresh();
dataGrid.Update();
}
但是这些代码不起作用。当点击All选项
复选框时,状态仍然在Checked->undeterminate->Unchecked->Checked->……那么,有人能建议如何从上面删除不确定状态吗?
我希望它是:Checked->Unchecked->Checked->Unchecked…尝试将设置为false
((DataGridViewCheckBoxCell)(dataGrid.CurrentCell)).ThreeState = false;
我不确定是否同意@Kyle Wang的解决方案。当您将当前单元格的
ThreeState
设置为false
时,基本上不允许出现“不确定”状态。这是用户单击“所有选项”复选框时所需的行为,但这不是更改“选项1”或“选项2”复选框时所需的行为
假设用户单击“所有选项”复选框并将其值更改为true
。此时,单元格“三状态”设置为false
,因此不确定的状态不是选项。然后,用户更改“选项1”或“选项2”复选框,其中一个为true
,另一个为false
。然后,代码必须将“All option”单元格的ThreeState
属性更改回true
,以便根据您的要求将其设置为不确定的
状态。我可以看到一个噩梦,跟踪每个单元格的状态“所有选项”单元格
此外,您可能需要注意“哪个”您选择执行某些操作的事件。例如,代码似乎正在连接两个网格事件:CurrentCellDirtyStateChanged
和CellValueChanged
。这是完全有效的,可以工作,但它可能有助于查看这些事件触发的频率。我没有检查这一点,因为我确信,如果您显示了多少次当事件触发时,您会发现它们触发的次数比您预期的要多。在下面的示例中,在测试事件时,可以直观地看到事件触发的次数。我建议您在当前代码中尝试此方法
考虑到这一点,显然“最佳”事件是gridsCellValueChanged
事件。不幸的是,该事件在用户“离开”之前不会触发单元格。通过一个复选框,我们希望在用户单击复选框时立即触发事件。一个可能有帮助的事件是gridsCellContentClick
事件。此事件将在用户单击“复选框”时立即触发。请记住,如果用户单击复选框“cell”,而不是“复选框”本身
使用此事件的一个问题是它何时触发。它是在网格中的复选框“值”实际更改之前触发的。幸运的是,因为我们知道它是一个复选框单元格,所以我们可以继续“提交”网格更改。然后我们将获得单元格的实际最终值
如果您创建一个新的“winform”项目,将一个DataGridView
和一个多行TextBox
放到表单上(如下所示),您应该能够测试下面的代码
我将所有初始化代码移到formsLoad
事件中,但是除了添加两个不同的行之外,代码是相同的
遍历网格CellContentClick
event:代码将文本添加到文本框中,以显示事件已触发(如前所述)。然后代码“提交”单元格中的更改。然后使用if
语句检查更改的单元格是“全部选项”列还是“选项”列之一s列。如果更改的单元格位于“所有选项”列中,则变量allOption
被设置为“所有选项”单元格的CheckState
值,选中、未选中或不确定
接下来,在每个状态的allOption
变量上执行switch
语句,选中、取消选中或不确定。如果状态更改为true
或false
,则代码只是将两个“选项”更改为相同的状态。显然,无需更改“All option”状态
private void Form1_Load(object sender, EventArgs e) {
dataTable = new DataTable();
dataTable.Columns.Add("Item");
dataTable.Columns.Add("All option", typeof(CheckState));
dataTable.Columns.Add("Option 1", typeof(bool));
dataTable.Columns.Add("Option 2", typeof(bool));
dataTable.Rows.Add("Item 1", CheckState.Unchecked, false, false);
dataTable.Rows.Add("Item 2", CheckState.Checked, true, true);
dataTable.Rows.Add("Item 3", CheckState.Indeterminate, false, true);
dataTable.Rows.Add("Item 4", CheckState.Indeterminate, true, false);
dataGrid.DataSource = dataTable;
}
private void dataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e) {
textBox1.Text += "CellContentClick" + Environment.NewLine;
dataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
if (dataGrid.Columns[e.ColumnIndex].Name == "All option") {
var allOption = (CheckState)dataGrid["All option", e.RowIndex].Value;
switch (allOption) {
case CheckState.Unchecked:
dataGrid["Option 1", e.RowIndex].Value = CheckState.Unchecked;
dataGrid["Option 2", e.RowIndex].Value = CheckState.Unchecked;
break;
case CheckState.Checked:
dataGrid["Option 1", e.RowIndex].Value = CheckState.Checked;
dataGrid["Option 2", e.RowIndex].Value = CheckState.Checked;
break;
case CheckState.Indeterminate:
dataGrid["Option 1", e.RowIndex].Value = CheckState.Unchecked;
dataGrid["Option 2", e.RowIndex].Value = CheckState.Unchecked;
dataGrid["All option", e.RowIndex].Value = CheckState.Unchecked;
// we changed the current All option cell so we need to refresh the edit
dataGrid.RefreshEdit();
break;
}
}
else {
if (dataGrid.Columns[e.ColumnIndex].Name == "Option 1" ||
dataGrid.Columns[e.ColumnIndex].Name == "Option 2") {
var op1Checked = (bool)dataGrid["Option 1", e.RowIndex].Value;
var op2Checked = (bool)dataGrid["Option 2", e.RowIndex].Value;
if (op1Checked && op2Checked) {
dataGrid["All option", e.RowIndex].Value = CheckState.Checked;
}
else {
if (!op1Checked && !op2Checked) {
dataGrid["All option", e.RowIndex].Value = CheckState.Unchecked;
}
else {
dataGrid["All option", e.RowIndex].Value = CheckState.Indeterminate;
}
}
}
}
}
如果“所有选项”单元格的当前状态为不确定,则表示一个选项为真,另一个为假。此“不确定”状态是由另一个选项复选框设置的。哪个单元格是true
或false
,与此无关,代码只是将所有状态更改为unchecked。注意:由于我们正在更改代码中的“all option”单元格,并且我们知道该单元格已提交到不确定的状态(我们不希望这样做),我们需要刷新中的编辑