【问题标题】:Changing the back colour on a specific row of a Datagridview更改 Datagridview 特定行的背景颜色
【发布时间】:2021-10-18 18:41:22
【问题描述】:

我尝试使用以下条件更改背面颜色。它不起作用。

private void frmJobStat_Load(object sender, EventArgs e)
{
    sql = "SELECT `jobno` AS JOB_NO,`lcode` AS LOCATION,iscompleted, iscannotrepair, isissued FROM `jobmaster`";
    config.Load_DTG(sql, dgvJobNo);

    dgvJobNo.Columns[1].Visible = false;
    //dgvJobNo.Columns[2].Visible = false;
    //dgvJobNo.Columns[3].Visible = false;
    //dgvJobNo.Columns[4].Visible = false;
    dgvJobNo.Columns[0].Width = 100;
    dgvJobNo.DefaultCellStyle.Format = "000000";

    for (int i = 0; i < dgvJobNo.Rows.Count - 1; i++)
    {
        if (Boolean.Parse(dgvJobNo.Rows[i].Cells[2].Value.ToString()))
        {
            dgvJobNo.Rows[i].DefaultCellStyle.BackColor = Color.Blue;
        }
    }

    //foreach (DataGridViewRow rw in dgvJobNo.Rows)
    //{
    //    if (rw.Cells[2].Value.ToString()=="1")
    //    {
    //        dgvJobNo.DefaultCellStyle.BackColor = Color.Red;
    //    }
    //}
}

我已经从表中加载了一个具有真/假值的列。如果是真的,我需要改变颜色。

谁能帮帮我?

【问题讨论】:

  • 这段代码在哪里执行?它似乎按预期工作。你有没有在行上设置断点…dgvJobNo.Rows[i].DefaultCellStyle.BackColor = Color.Blue;…看看解析是否成功?
  • 我在表单加载事件中执行。但不工作。
  • 经常加载太早。
  • 假设... “它不起作用。” ... 表示您没有收到任何错误,那么我建议您在if 语句上设置断点并仔细检查……dgvJobNo.Rows[i].Cells[2].Value.ToString()……回来了。我只是说,如果单元格值不是有效的Boolean 值,则使用Boolean.Parse 会引发格式异常。此外,如果“知道”单元格中有 true 值,这将是一个很好的调试起点。
  • RowPrePaint 事件。另请参阅CellFormatting 事件。

标签: c# winforms


【解决方案1】:

使用 DataGridView 的人经常倾向于直接摆弄 Cells 和值的显示方式。使用 DataBinding 更容易:使用 DataGridView.DataSource 将数据与其显示方式分开。

使用数据源

我对你在 DataGridView 中显示的内容一无所知,所以假设你想显示 Products。

所以在某个地方你有一个类可以从某个地方保存和检索产品。当然,您隐藏了数据是从数据库中获取的,以及如何获取的(DbConnection 和 DbCommand?或者可能是实体框架和 LINQ?)。您所知道的是,您可以存储产品并在以后检索它们:

interface IRepository
{
    int AddProduct(Product product)   // returns Id
    Product FetchProduct(int id);

    IEnumerable<Product> FetchProducts(...); // fetches several Products to display
    ...

哦,在我忘记之前:

class Product
{
    public int Id {get; set;}
    public string Name {get; set;}

    public decimal Price {get; set;}
    public int Stock {get; set;}
    ...
}

假设您有一个带有 DataGridView 的表单,您想在其中显示一些产品。使用 Visual Studio 设计器,您添加了一个 DataGridView 和一些列

在构造函数中:

public MyForm : ...
{
    InitializeComponent();

    this.columnId.DataPropertyName = nameof(Product.Id);
    this.columnName.DataPropertyName = nameof(Product.Name);
    this.columnPrice.DataPropertyName = nameof(Product.Price);
    ...
}

当然,您可以访问存储库和获取要显示的产品的方法:

private IRepository ProductRepository => ...

private IEnumerable<Product> FetchProductsToDisplay()
{
    return this.ProductRepository.FetchProducts(...);
}

现在要显示获取的产品,我们在 BindingList 中使用 DataGridView 的 DataSource:

private BindingList<Product> DisplayedProducts
{
    get => (BindingList<Product>)this.dataGridView1.DataSource;
    set => this.dataGridView1.DataSource = value;
}

private void ShowInitialProducts()
{
    this.DisplayedProducts = new BindingList<Product>( this.FetchProductsToDisplay().ToList());

当然,在加载表单时:

private void OnFormLoading(object sender, ...)
{
    this.ShowInitialProducts();
}

这足以显示所有产品。如果操作员添加或删除某些行,或编辑行的值,它们会自动更新。如果操作员表明他已经完成了对产品的编辑,例如通过单击确定按钮:

private void OnButtonOkClicked(object sender, ...)
{
    this.ProcessEditedProducts();
}

private void ProcessEditedProducts()
{
    ICollection<Product> displayedProducts = this.DisplayedProducts();
    // find out which Products are added / removed / changed
    this.ProcessProducts(displayedProducts);
}

顺便说一句,您是否注意到我的程序总是很小:它们只做一件事,它们服务于一个目的。这使它们易于理解、易于重用、易于测试和更改。

间奏曲:一些有用的功能

以下小方法可能会很方便。如果您有 DataGridViewRow,则可以通过 DataGridViewRow.DataBoundItem 获取行中显示的 Product。

// Get the Product that is displayed in row with rowIndex
private Product DisplayedProduct(int rowIndex)
{
    return (Product)this.dataGridView1.Rows[rowIndex].DataBoundItem;
}

// Get the Currently Selected Product
private Product CurrentProduct()
{
    return (Product)this.dataGridView1.CurrentRow.DataBoundItem;
}

// Get all Selected Products (if you allow multi-selecting
private IEnumerable<Product> GetSelectedProducts()
{
    return this.dataGridView1.SelectedRows.Cast<DataGridViewRow>()
        .Select(row => row.DataBoundItem)
        .Cast<Product>();
}

回到你的问题

显然,有一个谓词让你想给一些单元格一个不同的背景颜色。例如:如果库存为零,您想要红色,如果库存低,您想要橙色。否则你想要一个白色的背景

Color ZeroStockColor = Color.Red;
Color LowStockColor = Color.Orange;
int LowStockValue = 10;               // 10 or less: Stock is low

就在显示单元格的值之前,您有机会使用事件DataGridView.CellFormatting 格式化单元格。

如果显示股票的列正在格式化,我们要检查股票的价值。如果它是零,我们想要红色背景,如果它是低的,我们有一个橙色背景。

private void OnCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    // e contains the rowIndex and columnIndex
    if (e.ColumnIndex = this.columnStockValue.Index)
    {
        // Formatting the cell that contains the stock value
        Product productToFormat = this.DisplayedProduct(e.RowIndex);
        DataGridViewCell cellToFormat = this.dataGridView1
            .Rows[e.RowIndex].Cells[e.ColumnIndex];

        if (productToFormat.Stock == 0)
        {
            // no stock: RED!
            cellToFormat.Style.BackColor = ZeroStockColor;
        }
        else if (productToFormat.Stock <= LowStockValue)
        {
            // Low stock: Orange!
            cellToFormat.Style.BackColor = LowStockColor;
        }
        else
        {
            // enough stock: use default cell Style of this column
            cellToFormat.Style =  null;
        }
    }
}

如果DataGridViewCell.Style 不为空,则此样式用于格式化单元格。如果 Style 为 null,则使用 DataGridViewColumn.DefaultCellStyle,除非该值也为 null。在这种情况下,我们会走得更高:DataGridView.DefaultCellStyle

结论

如果您使用DataBinding,可以很容易地在DataGridView中显示您的数据并访问DataGridView中的对象:当前对象、选定对象或第10行显示的对象。

要格式化单元格,请使用DataGridViewCell.Style,或列中或DataGridView 中的DefaultCellStyle

使用事件DataGridView.CellFormatting 在单元格显示之前对其进行格式化。

【讨论】:

  • 非常感谢您的解释。我是 C# 的初学者。我还在学习。我正在尝试听从您的建议。
【解决方案2】:

它不起作用,因为在 C# 中,如果您仅通过赋值创建一个新对象,它将不会生成子引用,所以

 dgvJobNo.Rows[i].DefaultCellStyle.BackColor 

这里可能不存在。

你必须这样做

for (int i = 0; i < dgvJobNo.Rows.Count - 1; i++)
        {
            if (Boolean.Parse(dgvJobNo.Rows[i].Cells[2].Value.ToString()))
            {
var row= new Rows();
var a = new DefaultCellStyle();
a.BackColor= Color.Blue;
row.DefaultCellStyle = a;
                dgvJobNo.Rows[i] = row;
            }
        }

【讨论】:

  • 我没有不尊重的意思,但是……您的代码甚至不是有效的 C# .Net 代码。我也不同意你的说法……你为什么要说……dgvJobNo.Rows[i].DefaultCellStyle.BackColor……“这里不可能不存在。”……? … 如果它不存在,你会得到一个null 引用异常或索引越界异常。 OP 发布的代码有效,除非由于某种原因解析失败......其他事情正在发生。
  • 可能是一个案例,我曾经这样做过,它对我有用。我在这里没有确切的解决方案,只是分享它如何工作的基本想法。通常,它不会抛出空引用错误,因为没有可引用的内容。我曾经创建模型来绑定结构中的数据。
  • “一般情况下,它不会抛出空引用错误,因为没有可引用的内容。” ... ? …
  • 它不起作用,先生,这是说 dgvJobNo.Rows[i] = row;只读
  • 当我调用 dgvJobNo_CellFormatting 事件时,它可以工作。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 2013-11-22
  • 2013-04-12
  • 2016-05-27
相关资源
最近更新 更多