Link to home
Start Free TrialLog in
Avatar of rwheeler23
rwheeler23Flag for United States of America

asked on

How to set color of row inside a datagridview using C# based on a value in the row.?

I have placed a datagridview called  dgvTransferPOs onto a Winform using C#. What is being displayed is a list of purchase order numbers resulting from a SQL query. One of the columns in the query is called IsClosed. What I need is to change the color of the row to red if IsClosed = 1 otherwise use the default color if IsClosed =0. The dgv displays 10 records at a time. So if there are 20 records and the user scrolls down, the color needs to move as the slider is moved.
Avatar of it_saige
it_saige
Flag of United States of America image

Like this:

Form1.cs -
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace EE_Q29177136
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void OnCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 3)
            {
                var grid = sender as DataGridView;
                if (Convert.ToBoolean(grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value))
                {
                    grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
                }
            }
        }

        private void OnLoad(object sender, System.EventArgs e)
        {
            dataGridView1.DataSource = Enumerable.Range(0, 10).Select(i => new { Id = i, Name = $"Name{i}", Birthdate = DateTime.Now.AddMonths(-(i * 9)), IsWorking = (i & 1) == 0 }).ToList();
        }
    }
}

Open in new window

Form1.Designer.cs -
namespace EE_Q29177136
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.dataGridView1 = new System.Windows.Forms.DataGridView();
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
            this.SuspendLayout();
            // 
            // dataGridView1
            // 
            this.dataGridView1.AllowUserToAddRows = false;
            this.dataGridView1.AllowUserToDeleteRows = false;
            this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
            this.dataGridView1.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.dataGridView1.Location = new System.Drawing.Point(0, 0);
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.ReadOnly = true;
            this.dataGridView1.RowHeadersVisible = false;
            this.dataGridView1.Size = new System.Drawing.Size(521, 297);
            this.dataGridView1.TabIndex = 0;
            this.dataGridView1.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.OnCellFormatting);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(521, 297);
            this.Controls.Add(this.dataGridView1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.OnLoad);
            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.DataGridView dataGridView1;
    }
}

Open in new window

Produces the following output -User generated image-saige-
Avatar of rwheeler23

ASKER

So in my case where I may be displaying 10 purchase orders and the sixth PO is closed (IsClosed=1) only the sixth line will be red? I see what you are doing. You are applying this as the form loads and checking the value of IsClosed.
You got it.  Just make sure you use the correct column index.  ;)

-saige-
Please excuse my ignorance, but my data is sitting in a dataset as a result of executing a SQL query. How do I translate your code below to use what is sitting in my dataset?

        private void OnLoad(object sender, System.EventArgs e)
        {
            dataGridView1.DataSource = Enumerable.Range(0, 10).Select(i => new { Id = i, Name = $"Name{i}", Birthdate = DateTime.Now.AddMonths(-(i * 9)), IsWorking = (i & 1) == 0 }).ToList();
        }
This is what I have so far. No colors are changing.

        private void dgvTransferPOs_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 4)
            {
                MessageBox.Show("Her I am!");
                var grid = sender as DataGridView;
                if (Convert.ToBoolean(grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value))
                {
                    grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
                }
            }
        }

        private void frmJobTrnPOLookup_Load(object sender, EventArgs e)
        {
            //dgvTransferPOs.DataSource = Enumerable.Range(0, 10).Select(i => new { Id = i, txtp, VENDNAME, PODATE, REQDATE).ToList();
        }
There are four fields in the grid. The fifth field is the IsClosed column which I have set Visible to false. I can watch it go through each column and then the next row but the colors never change. I did set e.ColumnIndex == 5
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Interesting, I have changed the IsClosed field to now read "OPEN" or "CLOSED". I will make this column visible and then adjust the code to look for "CLOSED" for red otherwise white.
OK, I am real close with this. If I put a Messagebox.Show inside this as it displays each line they are either red or white. However, take out the messagebox and I can see the values in the grid for a split second but then I get the message "object not set to an instance of an object". It appears to run past the grid. How do I prevent this?


        private void dgvTransferPOs_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 4)
            {
                var grid = sender as DataGridView;
                if (grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "CLOSED")
                {
                    grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
                }
                else
                {
                    grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
                }
            }
        }
You should debug it in order to find out what is give the object reference exception.  If it were out of bounds you would get an error saying such.

-saige-
Debugging told me nothing useful. I see if go through 21 rows x 5 columns. It gets to the last column on the last row and crashes. Do I have this on the correct event?

        private void dgvTransferPOs_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 4)
            {
                var grid = sender as DataGridView;
                foreach (var row in grid.Rows.Cast<DataGridViewRow>())
                {
                    if (grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "CLOSED")
                    {
                        grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
                    }
                    else
                    {
                        grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;
                    }
                }
            }
        }
This event should work, if anything, you could try the DataBindingComplete event and go through the rows as I demonstrated above.

-saige-
Saige, thank you so much for your patience with me on this. Thanks to your help I now have working code. What I have below works perfectly. If I may ask one more question?
What does  [Browsable(false)] in the class do?

            [Browsable(false)]
            public bool IsClosed { get; set; }


        private void dgvTransferPOs_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            var grid = sender as DataGridView;
            if (Equals(grid, dgvTransferPOs))
            {
                // Using a well defined column
                foreach (var row in grid.Rows.Cast<DataGridViewRow>())
                {
                    // IsClosed is not visible, but we can still access the value
                    if (Convert.ToBoolean(row.Cells[5].Value))
                    {
                        row.DefaultCellStyle.BackColor = Color.Red;
                    }
                }
            }
            else
            {
                // Using a well defined type
                foreach (var row in grid.Rows.Cast<DataGridViewRow>())
                {
                    // IsWorking is not visible, but we can still access the value
                    if ((row.DataBoundItem as PODOC).IsClosed)
                    {
                        row.DefaultCellStyle.BackColor = Color.Red;
                    }
                    //else
                    //{
                    //    row.DefaultCellStyle.BackColor = Color.White;
                    //}
                }
            }
        }

        class PODOC
        {
            public string PONUM { get; set; }
            public DateTime PODATE { get; set; }
            public DateTime REQDATE { get; set; }
            public string POSTATUS { get; set; }

            [Browsable(false)]
            public bool IsClosed { get; set; }
        }
So Browsable is an attribute that tells consumers whether they should display the property.

The DataGridView control will not display properties that have the Browsable(false) attribute defined on them.

-saige-
Thank you for your invaluable assistance.