[英]Current cell cannot be set to an invisible cell in DataGridView WITHOUT DataSource
我有一个没有 DataSource 的dgv
C# DataGridView。
我有一个索引为c
的列,当另一列的单元格的值更改为某个值时(在CellValueChanged
事件处理程序中),该列设置为不可见:
dgv.Columns[c].Visible = false;
在修改单元格然后单击另一个单元格后调用CellValueChanged
事件处理程序。 问题是,当我单击即将设置为不可见的列时,我得到异常“当前单元格不能设置为不可见的单元格”,而如果我单击其他列之一,一切都很好。
我阅读了一些其他答案(例如this或this ),其中建议使用CurrencyManager.SuspendBinding
和CurrencyManager.ResumeBinding
。 但是这对我不起作用,因为DataSource
是 null。
有什么提示吗?
谢谢你。
在网格CellValueChanged
事件中将列设置为“不可见”的问题在于,虽然执行的 scope 在CellValueChanged
事件中,但网格不会为您提供有关用户单击/移动到“位置”的任何信息” 单元格值更改后。
仅这一点总是会留下隐藏列(在那种情况下)容易出错,因为我们不知道用户点击/移动的“位置”。 因此,很明显,如果我们想避免错误,我们将不得不在其他事件中“隐藏”该列。
您可能会遇到的另一个问题是,当您尝试“更改”网格“选定”单元格时,某些事件不喜欢它,这是我们希望在用户单击我们想要使其不可见的列时执行的操作。 我们需要将选定的单元格“更改”为其他单元格以避免错误。
鉴于此,下面是一种可能会有所帮助的 hacky 方法。 请注意,没有对代码进行大量测试,并且当用户单击第一列的 header 列(排序)时发生了一个问题/错误。 这导致了崩溃,我最终关闭了该列的“排序”。
下面的小示例使用此逻辑... 具有四 (4) 个文本列的DataGridView
设置在表单上并填充了一些数据。 网格中的ConditionColumn
列(第 0 列)是“条件”列,它具有从 0 到 19 的字符串值。 正是这一列将触发“何时”“隐藏” HideColumn
(第 2 列)。
如果在ConditionColumn,
则HideColumn
将被设置为不可见。 有一个小的 function AllCellsLessThan20
循环遍历网格中的所有行并检查ConditionColumn
单元格中是否有任何大于 20 的值。如果至少有一个单元格值大于 20,则 function 将返回 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);
}
}
接下来是 function 检查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;
}
}
}
正如我所说,它很老套,但它有一些警告。 希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.