如何避免 datagridrow 高亮功能在 Null 上爆炸?

How do I avoid datagridrow highlight function bombing out on Null?

我有一个函数,旨在突出显示某些单元格彼此不匹配的行。这一直有效,直到它碰到一个什么都不包含的单元格,然后它作为 nullrefexception 爆炸。我知道我在这里遗漏了一些简单的东西,但我正在用头撞墙试图弄清楚! 提前致谢。

        private void highlightrow()
    {
        int rowcnt = 0;
        dataGridView1.ClearSelection();
        int deviceNameColIndex = dataGridView1.Columns["cDeviceName"].Index;
        int deviceNameColIndex2 = dataGridView1.Columns["cDeviceName2"].Index;
        int driverVerColIndex = dataGridView1.Columns["cDriverVersion"].Index;
        int driverVerColIndex2 = dataGridView1.Columns["cDriverVersion2"].Index;
        int driverProviderName = dataGridView1.Columns["cdriverProviderName"].Index;
        int driverProviderName2 = dataGridView1.Columns["cdriverProviderName2"].Index;

        try
        {
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {

                rowcnt++;

                if (row.Cells[driverVerColIndex].Value.ToString() != row.Cells[driverVerColIndex2].Value.ToString() ||
                    row.Cells[driverProviderName].Value.ToString() != row.Cells[driverProviderName2].Value.ToString() ||
                    row.Cells[deviceNameColIndex].Value.ToString() != row.Cells[deviceNameColIndex2].Value.ToString()
                    )
                {
                    dataGridView1.DefaultCellStyle.SelectionBackColor = Color.YellowGreen;
                    row.Selected = true;
                }

            }
        }

        catch (NullReferenceException) { }
 }

How do I skip null cells?

谢谢你的想法。我之前尝试过检查 null 但仍然遇到问题,所以一直在寻找一些实际的例子。碰巧的是,我设法对它进行了排序,但仍然觉得可以做得更好:

private void highlightrow()
{
    int rowcnt = 0;
    dataGridView1.ClearSelection();
    int deviceNameColIndex = dataGridView1.Columns["cDeviceName"].Index;
    int deviceNameColIndex2 = dataGridView1.Columns["cDeviceName2"].Index;
    int driverVerColIndex = dataGridView1.Columns["cDriverVersion"].Index;
    int driverVerColIndex2 = dataGridView1.Columns["cDriverVersion2"].Index;
    int driverProviderName = dataGridView1.Columns["cdriverProviderName"].Index;
    int driverProviderName2 = dataGridView1.Columns["cdriverProviderName2"].Index;

    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
        rowcnt++;

        foreach (DataGridViewCell cell in row.Cells)
        {
            string val = cell.Value as string;
            if (String.IsNullOrEmpty(val))
            { }
            else
            {
                try
                {
                    if (
                    row.Cells[driverVerColIndex].Value.ToString() != row.Cells[driverVerColIndex2].Value.ToString() ||
                    row.Cells[driverProviderName].Value.ToString() != row.Cells[driverProviderName2].Value.ToString() ||
                    row.Cells[deviceNameColIndex].Value.ToString() != row.Cells[deviceNameColIndex2].Value.ToString()
                    )
                    {
                        dataGridView1.DefaultCellStyle.SelectionBackColor = Color.YellowGreen;
                        row.Selected = true;
                    }
                }
                catch { }
            }
        }

    }
}

我的评论没有冒犯的意思。我只是想推动您找到更好的解决方案。您是否选择尝试寻找更好的解决方案取决于您。为了捍卫我的评论,特别是关于 foreach 列循环产生的不良副作用......我只是想指出“为什么”这种方法会产生一些 undesired/unexpected 结果.如果它不是有用的评论,请原谅我。

使用当前发布的示例,下面是一种可能的“更好”方法,当试图避免空引用异常时,特别是在循环 DataGridView.

对于初学者来说,当遍历网格中的行并检查单元格值时,单元格值“总是”可能是 null. 在某些情况下,您“可能”假设单元格值不是 null, 然而,即使在极少数情况下,作为编码器,如果单元格“不知何故” null 并且代码不检查这个......然后代码崩溃。后果太严重了,不能忽略这个检查。

因此,当遍历网格的单元格时...在我们尝试调用它的 ToString 方法之前检查这些 null 值是明智的。

检查 null 值的一个地方是该行是否是网格“新”行。如果网格的 AllowUsersToAddRows 属性 设置为 true 并且网格数据源允许新行,那么可以保证该行中的单元格为空。因此,在遍历行时,检查这个新行将消除检查单元格的需要。我们知道它们都是 null 所以我们可以“跳过”那一行。

您可以考虑简单地将网格 AllowUserToAddRows 属性 更改为 false 并跳过此检查,但是,如果以后 属性 被更改怎么办到 true?如果我们“始终”检查这个“新”行,无论它是否存在,都将允许代码工作,而不管 AllowUserToAddRows 属性 是什么。

因此,foreach 循环遍历行的第一个检查将是对新行的检查……

foreach (DataGridViewRow row in dataGridView1.Rows) {
  if (!row.IsNewRow) { … //this row it NOT the new row … }

这消除了“新”行;但是,我们仍然需要检查每个单元格。在这种情况下,代码必须检查六 (6) 个 Cell.Value 是否为 null,然后代码将需要一次比较六 (6) 个值。使用一堆 if 语句可能会变得混乱。

因此,如果我们创建一个检查两个单元格值的方法,如果单元格值相等,returns true,如果不相等,则 false 可能会有所帮助。这应该会减少我们需要的 if 语句的数量。这个方法可能看起来像……

private bool CellsAreEqual(DataGridViewCell cell1, DataGridViewCell cell2) {
  if (cell1.Value == null && cell2.Value == null) {
    return false;
  }
  if (cell1.Value != null && cell2.Value != null) {
    return cell1.Value.ToString().Equals(cell2.Value.ToString());
  }
  else {
    // one cell is null the other cell is not null
    return false;
  }

代码逻辑假定,如果一个或两个单元格是 null,则单元格不相等。首先检查是否两个单元格都是 null 如果是 returns false. 如果一个单元格是 null 而另一个单元格不是 null,然后return false,否则我们可以安全地调用每个Cell.Value.ToString方法。

最后,使用上述方法和新的行信息,我们可以将 highlightrow 方法更改为...

private void highlightrow() {
  dataGridView1.ClearSelection();
  foreach (DataGridViewRow row in dataGridView1.Rows) {
    if (!row.IsNewRow) {
      if (!CellsAreEqual(row.Cells["cDriverVersion"], row.Cells["cDriverVersion2"]) ||
          !CellsAreEqual(row.Cells["cdriverProviderName"], row.Cells["cdriverProviderName2"]) ||
          !CellsAreEqual(row.Cells["cDeviceName"], row.Cells["cDeviceName2"])) {
        dataGridView1.DefaultCellStyle.SelectionBackColor = Color.YellowGreen;
        row.Selected = true;
      }
    }
    else {
      // ignore new row
    }
  }
}

我希望这是有道理的。