繁体   English   中英

当前单元格不能设置为 DataGridView 中没有数据源的不可见单元格

[英]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事件处理程序。 问题是,当我单击即将设置为不可见的列时,我得到异常“当前单元格不能设置为不可见的单元格”,而如果我单击其他列之一,一切都很好。

我阅读了一些其他答案(例如thisthis ),其中建议使用CurrencyManager.SuspendBindingCurrencyManager.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM