根据条件更改 datagridview 单元格颜色

Posted

技术标签:

【中文标题】根据条件更改 datagridview 单元格颜色【英文标题】:Changing datagridview cell color based on condition 【发布时间】:2013-10-23 04:50:31 【问题描述】:

我已将数据从数据库加载到 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;
             

【问题讨论】:

【参考方案1】:

我可能建议在每次调用 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 语句之后选择 case 更快。 它正在改变每个单元格的颜色【参考方案2】:

你需要这样做

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; 
        
    

同时也看看Cell Formatting

【讨论】:

这会不会非常低效?由于您每次重绘任何单元格时都会遍历所有记录。如果您采用这种方法,则整个 foreach 子句不必位于 CellFormatting 处理程序中,但应该是 dataGridView1_DataBindingComplete 或使用 var Myrow = dataGridView1.Rows[e.RowIndex] 而不是循环 这是一个糟糕的解决方案,代码按每个单元格迭代所有行。【参考方案3】:

Kyle 和 Simon 的回答严重浪费了 CPU 资源。 CellFormattingCellPainting 事件发生的次数太多,不应用于应用样式。这里有两种更好的方法:

如果您的 DataGridView 或至少决定单元格样式的列是只读的,您应该在 RowsAdded 事件中更改行的 DefaultCellStyle。此事件仅在添加新行时发​​生一次。那时应该评估条件并且应该在其中设置行的DefaultCellStyle。请注意,此事件也会在 DataBound 情况下发生。

如果您的 DataGridView 或那些列允许编辑,您应该使用 CellEndEditCommitEdit 事件来更改 DefaultCellStyle

【讨论】:

@dotNET 我知道帖子已经过时了——而且是一个很好的观点。如果您只想更改已更改的单个单元格而不是整行怎么办?并且假设只有绑定源被更改并且单元格编辑事件没有被调用? @Ken:您仍然可以使用RowsAdded 事件。而不是使用行的DefaultCellStyle,在这种情况下,您应该使用所需单元格的Style 属性。如果你需要根据数据源的变化来改变风格,你应该监听数据源本身引发的事件并改变其中的风格。例如,如果您使用DataTable 作为数据源,则可以监听DataTableRowChangedColumnChanged 事件。【参考方案4】:

假设您必须通过了解两件事来为某个单元格(不是该行的所有单元格)着色:

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

在这种情况下,您必须使用事件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;
       
     

你可以在这里看到结果

因此,您可以在此处按名称访问列中行的某些单元格 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;
    
  

【讨论】:

【参考方案5】:
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;
    

这对我来说非常有用。即使更改了一行,也会处理相同的事件。

【讨论】:

【参考方案6】:

无需循环即可实现如下。

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);
        
    

【讨论】:

【参考方案7】:
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;
        
    

【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。【参考方案8】:
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;

            
        
    

【讨论】:

【参考方案9】:

自从我在 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");
            

        
    

【讨论】:

【参考方案10】:

很惊讶没有人提到一个简单的if 语句可以确保您的循环仅在每种格式中执行一次(在第一行的第一列上)。

    private void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
    
        // once per format
        if (e.ColumnIndex == 0 && e.RowIndex == 0)
        
            foreach (DataGridViewRow row in dgv.Rows)
                if (row != null)
                    row.DefaultCellStyle.BackColor = Color.Red;
        
    

【讨论】:

【参考方案11】:

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

OP 已经完成了 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

【讨论】:

【参考方案12】:
//After Done Binding DataGridView Data
foreach(DataGridViewRow DGVR in DGV_DETAILED_DEF.Rows)

    if(DGVR.Index != -1)
    
        if(DGVR.Cells[0].Value.ToString() == "البدلات")
        
            CurrRType = "البدلات";
            DataGridViewCellStyle CS = DGVR.DefaultCellStyle;
            CS.BackColor = Color.FromArgb(0,175,100);
            CS.ForeColor = Color.FromArgb(0,32,15);

            CS.Font = new Font("Times New Roman",12,FontStyle.Bold);
            CS.SelectionBackColor = Color.FromArgb(0,175,100);
            CS.SelectionForeColor = Color.FromArgb(0,32,15);
            DataGridViewCellStyle LCS = DGVR.Cells[DGVR.Cells.Count - 1].Style;
            LCS.BackColor = Color.FromArgb(50,50,50);
            LCS.SelectionBackColor = Color.FromArgb(50,50,50);
        
        else if(DGVR.Cells[0].Value.ToString() == "الإستقطاعات")
        
            CurrRType = "الإستقطاعات";
            DataGridViewCellStyle CS = DGVR.DefaultCellStyle;
            CS.BackColor = Color.FromArgb(175,0,50);
            CS.ForeColor = Color.FromArgb(32,0,0);
            CS.Font = new Font("Times New Roman",12,FontStyle.Bold);
            CS.SelectionBackColor = Color.FromArgb(175,0,50);
            CS.SelectionForeColor = Color.FromArgb(32,0,0);
            DataGridViewCellStyle LCS = DGVR.Cells[DGVR.Cells.Count - 1].Style;
            LCS.BackColor = Color.FromArgb(50,50,50);
            LCS.SelectionBackColor = Color.FromArgb(50,50,50);
        
    

【讨论】:

【参考方案13】:

简单一点

private void dataGridView1_cellformatting(object sender,DataGridViewCellFormattingEventArgs e)

     var amount = (int)e.Value;

     // return if rowCount = 0
     if (this.dataGridView1.Rows.Count == 0)
         return;

     if (amount > 0)
         e.CellStyle.BackColor = Color.Green; 
     else
         e.CellStyle.BackColor = Color.Red;


看看cell formatting

【讨论】:

以上是关于根据条件更改 datagridview 单元格颜色的主要内容,如果未能解决你的问题,请参考以下文章

根据值更改单元格颜色

ReactJS 7 - 如何根据其值有条件地仅更改表格单元格(而不是行)的背景颜色?

更改 datagridview 行中单个单元格的样式

设置datagridview单元格背景颜色[重复]

对于使用“DataGridView”的 Windows 窗体应用程序,如何检查数据源中的值并更改单独单元格的颜色?

还原 datagridview 控件中的单元格样式更改?