基于条件改变datagridview单元格颜色

36

我已经从数据库加载数据到datagridview中,并有两列目标值和容量,其中容量>目标值,那么容量单元格应该是绿色的,如果容量<目标值,则容量应该是红色的。我尝试过了,但我做不到。

private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
    if (dataGridView1.Rows.Count > 0 && dataGridView1.Columns.Count > 0)
    {
        foreach (DataGridViewRow r in dataGridView1.Rows)
        {
            if (Volume > target value)
            {
                cell.Style.BackColor = Color.AliceBlue;
            } 
13个回答

30

我建议不要在每次调用CellFormating时循环遍历每一行,因为它会在需要刷新单个行的每个时间被调用。

Private Sub dgv_DisplayData_Vertical_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles dgv_DisplayData_Vertical.CellFormatting
        Try

            If dgv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() = "6" Then

                e.CellStyle.BackColor = Color.DimGray
            End If
            If dgv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() = "5" Then
                e.CellStyle.BackColor = Color.DarkSlateGray
            End If
            If dgv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() = "4" Then
                e.CellStyle.BackColor = Color.SlateGray
            End If
            If dgv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() = "3" Then
                e.CellStyle.BackColor = Color.LightGray
            End If
            If dgv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() = "0" Then
                e.CellStyle.BackColor = Color.White
            End If

        Catch ex As Exception

        End Try

    End Sub

晚点评论:这段代码可以改进。Dim value As String = gv_DisplayData_Vertical.Rows(e.RowIndex).Cells("LevelID").Value.ToString() Select Value case "1" e.CellStyle.BackColor = Color.DimGray Exit Select EndSelect 改进后的代码更短,更易读,并且使用选择语句比第三个if语句更快。 - Ken
它正在改变每个单元格的颜色。 - Faizan Mubasher

28

你需要做这件事

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    foreach (DataGridViewRow Myrow in dataGridView1.Rows) 
    {            //Here 2 cell is target value and 1 cell is Volume
        if (Convert.ToInt32(Myrow .Cells[2].Value)<Convert.ToInt32(Myrow .Cells[1].Value))// Or your condition 
        {
            Myrow .DefaultCellStyle.BackColor = Color.Red; 
        }
        else
        {
            Myrow .DefaultCellStyle.BackColor = Color.Green; 
        }
    }
}

同时也请查看单元格格式


26
这样做效率不会很低吗?因为每次重绘任何单元格时,都要迭代所有记录。如果采用这种方法,整个“foreach”子句不必放在CellFormatting处理程序中,而应该是“dataGridView1_DataBindingComplete”。 - 40pro
5
建议使用 var Myrow = dataGridView1.Rows[e.RowIndex],而不是进行循环操作。 - Rob Sedgwick
4
这是一个糟糕的解决方案,代码会逐个单元格地迭代所有行。 - dlopezgonzalez
正如@40pro所说,它真的很慢,在有19,000,00条记录时数据显示非常非常非常慢。 - sam

24
Kyle和Simon的答案浪费了大量的CPU资源。 CellFormatting和CellPainting事件发生的次数太多了,不应该用于应用样式。以下是两种更好的方法:
如果您的DataGridView或至少决定单元格样式的列是只读的,则应在RowsAdded事件中更改行的DefaultCellStyle。当添加新行时,此事件仅发生一次。应在那个时候评估条件并设置行的DefaultCellStyle。请注意,此事件也适用于数据绑定情况。
如果您的DataGridView或这些列允许编辑,则应使用CellEndEdit或CommitEdit事件来更改DefaultCellStyle。

@dotNET 我知道这篇文章已经有点老了,但是提出的观点非常好。如果你只想改变单个单元格而不是整行怎么办?假设只有绑定源被更改而单元格编辑事件尚未被调用呢? - Ken
@Ken:你仍然可以使用RowsAdded事件。在这种情况下,你应该使用所需单元格的Style属性,而不是使用行的DefaultCellStyle。如果你需要根据数据源更改样式,你应该监听数据源本身引发的事件并在其中更改样式。例如,如果你正在使用DataTable作为数据源,你可以监听DataTableRowChangedColumnChanged事件。 - dotNET

5

假设您需要通过知道两件事情来给某个单元格(而不是整行的所有单元格)上色:

  1. 列的名称或索引。
  2. 将在单元格内的值。

在这种情况下,您需要使用事件CellFormatting

在我的情况下,我像这样使用

private void DgvTrucksMaster_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
     foreach (DataGridViewRow row in dgvTrucksMaster.Rows)
     {
       if (Convert.ToInt32(row.Cells["Decade1Hours"].Value) > 0)
       {
          row.Cells["Decade1Hours"].Style.BackColor = Color.LightGreen;
       }
       else if (Convert.ToInt32(row.Cells["Decade1Hours"].Value) < 0)
       {
          // row.DefaultCellStyle.BackColor = Color.LightSalmon; // Use it in order to colorize all cells of the row

          row.Cells["Decade1Hours"].Style.BackColor = Color.LightSalmon;
       }
     }
}

您可以在此处查看结果。

enter image description here

因此,您可以通过其名称访问行中某个列的特定单元格 row.Cells["Decade1Hours"]

您如何知道这个名称? 好吧,在我的情况下,我像这样创建了 DataGridView 的列。

var Decade1Hours = new DataGridViewTextBoxColumn()
{
   Name = "Decade1Hours",
   Width = 50,
   DataPropertyName = "Decade1Hours",
   ReadOnly = true,
   DefaultCellStyle = new DataGridViewCellStyle()
       {
        Alignment = DataGridViewContentAlignment.MiddleCenter,
        ForeColor = System.Drawing.Color.Black,
        Font = new Font(font, FontStyle.Bold),
        Format = "n2"
      },
   HeaderCell = new DataGridViewColumnHeaderCell()
      {
          Style = new DataGridViewCellStyle()
               {
                 Alignment = DataGridViewContentAlignment.MiddleCenter,
                 BackColor = System.Drawing.Color.Blue
               }
       }
};
Decade1Hours.HeaderText = "Дек.1";
dgvTrucksMaster.Columns.Add(Decade1Hours);

好的...如果你需要给某些行中的单元格着色,如1、4、5和8,你需要使用单元格索引(从0开始)。

代码将如下所示:

 private void DgvTrucksMaster_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
  foreach (DataGridViewRow row in dgvTrucksMaster.Rows)
  {
    if (Convert.ToInt32(row.Cells[1].Value) > 0 )
    {
      row.Cells[1].Style.BackColor = Color.LightGreen;
    }
  }
}

3
private void dataGridView1_DataBindingComplete(object sender DataGridViewBindingCompleteEventArgs e)
{
    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
        if (Convert.ToInt32(row.Cells["balaceAmount"].Value) == 0)
        {
            row.DefaultCellStyle.BackColor = Color.Yellow;
        }
        else
        {
            row.DefaultCellStyle.BackColor = Color.White;
        }
    }
}

1
虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。 - adiga

3
foreach (DataGridViewRow row in dgvWebData.Rows)
{
    if (Convert.ToString(row.Cells["IssuerName"].Value) != Convert.ToString(row.Cells["SearchTermUsed"].Value))
    {
        row.DefaultCellStyle.BackColor = Color.Yellow;
    }
    else
    {
        row.DefaultCellStyle.BackColor = Color.White;
    }
}

这对我非常有效。即使行发生更改,相同的事件也会处理它。

2

我已经有一段时间没有在SO上发布任何帖子了,但我们现在开始吧。

使用_RowsAddedEvent为您的网格单元格应用自定义样式,其他所有内容都会消耗太多CPU。如果您现在提出这个问题,那么CPU周期对您非常重要。

因此,以下是根据底层数据绑定项的值来绘制单元格的代码。

    private void grid_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
    {
        for ( int i = e.RowIndex; i <= e.RowIndex + e.RowCount - 1; i++)
        {
            var row = grid.Rows[i]; 
            var item = row.DataBoundItem as MovieViewerDataItem;
            if (item == null) continue;

            var cell = row.Cells["FullPath"]; 

            if ( item.FullPath.StartsWith("u:", StringComparison.InvariantCultureIgnoreCase))
            {
                cell.Style.BackColor = System.Drawing.ColorTranslator.FromHtml("#FFF2CC");
            }
            else if( item.FullPath.StartsWith("m:", StringComparison.InvariantCultureIgnoreCase))
            {
                cell.Style.BackColor = System.Drawing.ColorTranslator.FromHtml("#E2EFDA");
            }

        }
    }

1
不使用循环,可以像下面这样实现。
private void dgEvents_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {

        FormatRow(dgEvents.Rows[e.RowIndex]);

    }

private void FormatRow(DataGridViewRow myrow)
    {
        try
        {
            if (Convert.ToString(myrow.Cells["LevelDisplayName"].Value) == "Error")
            {
                myrow.DefaultCellStyle.BackColor = Color.Red;
            }
            else if (Convert.ToString(myrow.Cells["LevelDisplayName"].Value) == "Warning")
            {
                myrow.DefaultCellStyle.BackColor = Color.Yellow;
            }
            else if (Convert.ToString(myrow.Cells["LevelDisplayName"].Value) == "Information")
            {
                myrow.DefaultCellStyle.BackColor = Color.LightGreen;
            }
        }
        catch (Exception exception)
        {
            onLogs?.Invoke(exception.Message, EventArgs.Empty);
        }
    }

1
private void dataMain_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    {
        if (dataMain.Columns[e.ColumnIndex].Name == "colStatus")
        {
            if (int.Parse(e.Value.ToString()) == 2)
            {
                dataMain.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.OrangeRed;
                dataMain.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.White;

            }
        }
    }

0

我知道这是一个旧帖子,但我在2018年找到了这里的方法,所以也许其他人也会。在我看来,原帖作者的方法(使用dgv_DataBindingComplete事件)比提供的任何答案都要好。在撰写本文时,所有答案都是使用绘图事件或单元格格式化事件编写的,这似乎效率低下。

原帖作者已经完成了99%的工作,他们只需要循环遍历行,测试每行的单元格值,并设置BackColor,ForeColor或其他您想要设置的属性即可。

请原谅vb.NET语法,但我认为它足够接近C#,应该很清楚。

Private Sub dgvFinancialResults_DataBindingComplete Handles dgvFinancialResults.DataBindingComplete
            Try
                Logging.TraceIt()
                For Each row As DataGridViewRow in dgvFinancialResults.Rows
                    Dim invoicePricePercentChange = CSng(row.Cells("Invoice Price % Change").Value)
                    Dim netPricePercentChange = CSng(row.Cells("Net Price % Change").Value)
                    Dim tradespendPricePercentChange = CSng(row.Cells("Trade Spend % Change").Value)
                    Dim dnnsiPercentChange = CSng(row.Cells("DNNSI % Change").Value)
                    Dim cogsPercentChange = CSng(row.Cells("COGS % Change").Value)
                    Dim grossProfitPercentChange = CSng(row.Cells("Gross Profit % Change").Value)


                    If invoicePricePercentChange > Single.Epsilon Then
                        row.Cells("Invoice Price % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("Invoice Price % Change").Style.ForeColor = Color.Red
                    End If

                    If netPricePercentChange > Single.Epsilon Then
                        row.Cells("Net Price % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("Net Price % Change").Style.ForeColor = Color.Red
                    End If

                    If tradespendPricePercentChange > Single.Epsilon Then
                        row.Cells("Trade Spend % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("Trade Spend % Change").Style.ForeColor = Color.Red
                    End If

                    If dnnsiPercentChange > Single.Epsilon Then
                        row.Cells("DNNSI % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("DNNSI % Change").Style.ForeColor = Color.Red
                    End If

                    If cogsPercentChange > Single.Epsilon Then
                        row.Cells("COGS % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("COGS % Change").Style.ForeColor = Color.Red
                    End If

                    If grossProfitPercentChange > Single.Epsilon Then
                        row.Cells("Gross Profit % Change").Style.ForeColor = Color.Green
                    Else
                        row.Cells("Gross Profit % Change").Style.ForeColor = Color.Red
                    End If
                Next
            Catch ex As Exception
                Logging.ErrorHandler(ex)
            End Try
        End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接