在网格CellValueChanged 事件中将列设置为“不可见”的问题在于,虽然执行范围在CellValueChanged 事件中,但网格不会为您提供有关“位置”的任何信息单元格值更改后,用户单击/移动“到”。
仅此一项总是会导致隐藏列(在那种情况下)容易出错,因为我们不知道用户点击/移动的“位置”。因此,很明显,如果我们想避免该错误,我们将不得不在其他事件中“隐藏”该列。
您可能遇到的另一个问题是,当您尝试“更改”网格“选定”单元格时,某些事件不喜欢它,这是我们希望在用户单击我们想要的列时执行的操作使隐形。我们需要将选定的单元格“更改”为其他单元格以避免错误。
鉴于此,以下是一种可能会有所帮助的 hacky 方法。请注意,没有对代码进行大量测试,并且当用户单击第一列的列标题(进行排序)时发生了一个问题/错误。这导致了崩溃,我最终关闭了该列的“排序”。
下面的小示例使用此逻辑... 一个带有四 (4) 个文本列的 DataGridView 被设置在一个表单上并填充了一些数据。网格中的ConditionColumn(第 0 列)是“条件”列,它的字符串值范围为 0-19。正是这一列将触发“何时”“隐藏”HideColumn(第 2 列)。
如果在ConditionColumn, 的任何单元格中输入了大于二十 (20) 的值,那么HideColumn 将被设置为不可见。有一个小函数 AllCellsLessThan20 循环遍历网格中的所有行并检查 ConditionColumn 单元格中是否有任何大于 20 的值。如果至少有一个单元格值大于 20,则该函数将返回 false .这用于打开或关闭隐藏列,这样如果ConditionColumn 中的所有单元格都小于 20,则将显示该列。否则,如果一个或多个单元格大于 20,则该列将被隐藏。
为避免上述错误,代码会将列设置为在网格SelectionChanged 事件中不可见。如果用户以任何方式选择另一个单元格……单击、制表键或箭头键,此事件将在 CellValueChanged 事件“之后”触发。我们将检查几件事以确定是否需要隐藏或显示该列。
显然,因为这个事件是在CellValueChange 事件触发之后调用的,所以网格不会给我们任何关于之前选择的单元格“在哪里”的信息。因此,全局变量。在CellValueChanged 事件中设置这些全局值将使它们在SelectionChanged 事件中可用。
也许是一些变量,例如:
ColumnShown :bool 指示列当前是隐藏还是显示。
ValueGreaterThan20:bool 表示ConditionColumn 中的任何值是否大于 20
和 PreviousRow : int 表示最后一个“已更改”单元格的行索引。
bool ColumnShown = true;
bool ValueGreaterThan20 = false;
int PreviousRow = 0;
为网格列设置一些有用的名称以避免任何索引问题,然后用一些测试数据填充网格。
public Form1() {
InitializeComponent();
dataGridView1.Columns[0].Name = "ConditionColumn";
dataGridView1.Columns[0].HeaderText = "Condition";
dataGridView1.Columns[2].Name = "HideColumn";
dataGridView1.Columns[2].HeaderText = "Hide Column";
}
private void Form1_Load(object sender, EventArgs e) {
FillGrid();
}
private void FillGrid() {
for (int i = 0; i < 20; i++) {
dataGridView1.Rows.Add(i, "C1R" + i, "C2R" + i, "C3R" + i);
}
}
Next 是检查ConditionColumn 中是否有任何值大于20 的函数。
private bool AllCellsLessThan20() {
foreach (DataGridViewRow row in dataGridView1.Rows) {
if (row.Cells[0].Value != null) {
string sValue = row.Cells["ConditionColumn"].Value.ToString();
if (int.TryParse(sValue, out int value)) {
if (value > 20) {
return false;
}
}
}
}
return true;
}
接下来是网格CellValueChanged 事件。这里我们只需要检查两件事:1) 列 0 ConditionColumn 中的值是否发生了变化,并且由于该列中的值确实发生了变化,我们需要检查所有值。如果任何值超过 20,则将变量 ValueGreaterThan20 设置为 true,否则设置为 false。此外,我们将保存更改单元格的行索引 (PreviousRow),因为我们希望在 SelectionChanged 事件中使用它。
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (e.ColumnIndex == 0) {
if (AllCellsLessThan20())
ValueGreaterThan20 = false;
else
ValueGreaterThan20 = true;
}
PreviousRow = e.RowIndex;
}
SelectionChanged 事件如下。我知道这可能更紧凑。首先检查该列是显示还是隐藏。
如果该列已经“隐藏”,那么我们只需要检查以确保ConditionColumn 中至少有一个值大于20,然后将其隐藏。如果所有值都小于 20,那么我们要取消隐藏该列。
如果列不是“隐藏”的,那么我们检查是否有任何值大于 20。如果没有值大于 20,则让列可见。
如果列不是“隐藏”的,并且有一个或多个值大于 20,那么我们需要检查当前选择是否是我们要隐藏的列。如果当前选择不是我们想要隐藏的列,那么只需隐藏它,因为我们知道这不会引发错误。
最后,如果该列没有“隐藏”并且有一个大于 20 的值并且当前选择是我们要隐藏的列。在这种情况下,代码会将CurrentCell 设置/更改为PreviousRow 中的第一个单元格。然后将列设置为不可见,并设置全局变量ColumnShown.
在我的测试中,如果用户将第 0 列中的单元格更改为大于 20 的值,然后“单击”第 2 列中的单元格HideColumn,则不会弹出错误并且选择更改为第一个上一行的单元格。
private void dataGridView1_SelectionChanged(object sender, EventArgs e) {
if (ColumnShown) {
if (ValueGreaterThan20) {
int curColIndex = dataGridView1.CurrentCell.ColumnIndex;
if (dataGridView1.Columns[curColIndex].Name == "HideColumn") {
dataGridView1.CurrentCell = dataGridView1.Rows[PreviousRow].Cells["ConditionColumn"];
dataGridView1.CurrentCell.Selected = true;
}
dataGridView1.Columns["HideColumn"].Visible = false;
ColumnShown = false;
}
}
else {
if (!ValueGreaterThan20) {
dataGridView1.Columns["HideColumn"].Visible = true;
ColumnShown = true;
}
}
}
正如我所说,它很老套,但有一些注意事项。希望这会有所帮助!