根据值改变DataGridView列的颜色

3

我尝试更改DataGridView中列的背景颜色,根据其值进行相应更改。以下是我的代码。但是,在if语句中出现错误。

如果列的值小于零,我想将列的背景颜色更改为Color.Red。

private void DataColor()
{
    foreach (DataGridViewColumn col in MyDataGrid.Columns)
    if (Convert.ToInt32(col[5].Value) < 0)
    {
        MessageBox.Show("Test");

    }
}

我需要的输出:

输出


1
使用CellFormatting事件格式化单元格+ col是DataGridViewColumn,它没有索引器:col [5]没有意义。您正在尝试获取Cell.Value,因此请迭代行,最终 - 看起来您不想更改整个列的颜色,而是特定值具有特定值的特定单元格的背景颜色。请注意,5实际上是正确的列:使用名称而不是索引(如MyDataGrid ["SomeColumnName", e.RowIndex])-澄清意图。 - Jimi
2个回答

3
使用.NET Framework 4.8版本,尝试以下代码是否适用于您。将DataGridView添加到新表单中,添加下面的代码,并将表单名称更改为您表单的名称。
完整代码请查看:此处 示例图片:enter image description here
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace DataGridViewCellFormatting1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Shown += OnShown;
        }

        private void OnShown(object sender, EventArgs e)
        {
            dataGridView1.DataSource = MockedDataTable.Table();
            dataGridView1.CellFormatting += DataGridView1OnCellFormatting;
        }

        private const string _amountColumnName = "Amount";
        private void DataGridView1OnCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (!dataGridView1.Columns[e.ColumnIndex].Name.Equals(_amountColumnName)) return;
            if (e.Value == null || !int.TryParse(e.Value.ToString(), out var amount)) return;
            
            dataGridView1.Rows[e.RowIndex].Cells[_amountColumnName].Style.BackColor = amount >0 ? 
                Color.Empty : 
                Color.Red;
        }
    }

    public class MockedDataTable
    {
        public static DataTable Table()
        {
            var dt = new DataTable();

            dt.Columns.Add(new DataColumn()
            {
                ColumnName = "id", 
                DataType = typeof(int), 
                AutoIncrement = true, 
                AutoIncrementSeed = 1
            });
            
            dt.Columns.Add(new DataColumn() { ColumnName = "Amount", DataType = typeof(int) });

            dt.Rows.Add(null, 200);
            dt.Rows.Add(null, 1000);
            dt.Rows.Add(null, -3200);
            dt.Rows.Add(null, -300);
            dt.Rows.Add(null, 500);


            return dt;
        }
    }
}

除了检查 e.Value == null 之外,还应该检查 DBNull.Value 的值。 - Jimi
1
同意关于 DBNull.Value 的内容。 - Karen Payne

1

看着你想要的输出:

你并不想改变整个列的背景颜色,而是想改变包含小于零的值的单元格的颜色。


首先,您需要获取单元格。这可以通过迭代所有行(MyDataGrid.Rows)来完成。每一行都是DataGridViewRow类型,因此可以通过列位置访问每个单元格 - row.Cells[i]。每个单元格都是DataGridViewCell类型。在那里,您可以检查单元格的Value属性。 更动态的方法是迭代所有行的所有单元格(row.Cells),并检查cell.OwningColumn的标题。如果它等于您想要的列标题,则可以检查单元格的值。如果符合您的条件,可以通过定位底层样式-例如cell.Style.BackColor = Color.Red;来开始着色背景颜色。
这可以通过以下示例实现:
public partial class Form1 : Form
{
    private readonly DataGridView _myGrid;

    public Form1()
    {
        InitializeComponent();
        this.Load += this.Form1_Load;

        _myGrid = new DataGridView
        {
            DataSource = new[]
            {
                new {Name = "ABC", Amount = 2}, new {Name = "DEF", Amount = 3}, new {Name = "XYZ", Amount = -2}
            }
        };

        this.Controls.Add(_myGrid);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        foreach (DataGridViewRow row in _myGrid.Rows)
        {
            var cell = row.Cells[1];
            if (cell.Value is int val && val < 0)
            {
                cell.Style.BackColor = Color.Red;
            }          

            // A little bit more secure, if you are not sure which index the column has.
            /*
            foreach (DataGridViewCell cell in row.Cells)
            {
                if (string.Equals(cell.OwningColumn.HeaderText, "Amount"))
                {
                    if (cell.Value is int val && val < 0)
                    {
                        cell.Style.BackColor = Color.Red;
                    }
                }
            }
            */
        }
    }
}

这会导致以下输出。

Output|Result


回应您的评论:

我正在使用1.0版本[...] 但是有一个问题,我的数据网格的数据源来自SQL Server。 因此,如果列中有任何空值,程序会崩溃。 我该如何避免崩溃?

您可以使用int val = Convert.ToInt32(cell.Value);而不是模式匹配。为了避免在null值上出现System.NullReferenceExeption,您可以添加一个null检查。 如果从数据库接收到null值,则可能是DBNull.Value,它不等于null,因此您可以添加一个DBNull检查。

if (cell.Value == null || DBNull.Value.Equals(cell.Value))
{
    continue;
}

int val = Convert.ToInt32(cell.Value);
if (val < 0)
{
    cell.Style.BackColor = Color.Red;
}

为了避免出现 System.FormatException,如果你的列中可能包含除整数以外的内容,你可以使用 Int32.TryParse 而不是 Convert.ToInt32() - 同时进行空值检查。
 int val;
 if (Int32.TryParse(cell.Value.ToString(), out val))
 {
     if (val < 0)
     {
         cell.Style.BackColor = Color.Red;
     }
 }

但要小心:虽然Convert.ToInt32(cell.Value)也会将十进制数转换为int,但Int32.TryParse(cell.Value.ToString(), out val)会返回false


网站注释: 有更智能的解决方案,但这是我首先想到的。

例如:
正如Jimi评论中建议的那样:"使用CellFormatting事件格式化单元格"


它给我这个错误:"CS0103名称'val'在当前上下文中不存在。" - Swen22
你使用的是哪个版本的C#? 我的代码依赖于>= C#7 - 参见模式匹配,否则你可以使用int val = Convert.ToInt32(cell.Value); - Martin Backasch
我正在使用1.0版本,你提供的解决方案已经奏效了。非常感谢你的时间!但是有一个问题,我的datagrid的数据源来自于sql server。所以如果列上有任何空值,程序就会崩溃。我该如何避免它崩溃? - Swen22

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