Change Row background color based by cell value
-
Hi all, I have searched whole day now, for a solution that could fit my needs, yet again, I have to hope that some of your pro's here can help me getting closerto a solution. I'm using DataGridView in C# WinForms to show 6 coloumns (CustomerName, Subscribers, unsubcribed, specialCases, potential, percentage connected in %), it would look like:
CustomerName 20 4 0 24 20/24*100=83%
CustomerName2 12 10 1 22 12/22*100=55%etc. And the rows just continue basedon the number of customers of cause. Now, thats ain't any problem, and I get all my data proper as wanted. Now I want to make it a little bit more useful, and HIGHLIGHT every cell/row with a lightRed color, where the percentage is BELOW 70% (like row number 2 in my example). I have try'd with:
private void grid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemDeleted)
{
DataGridViewCellStyle red = grid.DefaultCellStyle.Clone();
red.BackColor = Color.LightPink;foreach (DataGridViewRow r in grid.Rows) { if ((int)r.Cells\["nummer6"\].Value < 70) { r.DefaultCellStyle = red; } } } }
or with a more similar code:
foreach (DataGridViewRow row in grid.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.ColumnIndex == 5)
{
if ((int)cell.Value < 70)
{
row.DefaultCellStyle.BackColor = Color.LightPink;
}
}
}
}But no matter what, then I can't get the backColor changed on rows where the % value in the last column cell is below 70%. :( Any ideas and help are preciated....
-
Hi all, I have searched whole day now, for a solution that could fit my needs, yet again, I have to hope that some of your pro's here can help me getting closerto a solution. I'm using DataGridView in C# WinForms to show 6 coloumns (CustomerName, Subscribers, unsubcribed, specialCases, potential, percentage connected in %), it would look like:
CustomerName 20 4 0 24 20/24*100=83%
CustomerName2 12 10 1 22 12/22*100=55%etc. And the rows just continue basedon the number of customers of cause. Now, thats ain't any problem, and I get all my data proper as wanted. Now I want to make it a little bit more useful, and HIGHLIGHT every cell/row with a lightRed color, where the percentage is BELOW 70% (like row number 2 in my example). I have try'd with:
private void grid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemDeleted)
{
DataGridViewCellStyle red = grid.DefaultCellStyle.Clone();
red.BackColor = Color.LightPink;foreach (DataGridViewRow r in grid.Rows) { if ((int)r.Cells\["nummer6"\].Value < 70) { r.DefaultCellStyle = red; } } } }
or with a more similar code:
foreach (DataGridViewRow row in grid.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.ColumnIndex == 5)
{
if ((int)cell.Value < 70)
{
row.DefaultCellStyle.BackColor = Color.LightPink;
}
}
}
}But no matter what, then I can't get the backColor changed on rows where the % value in the last column cell is below 70%. :( Any ideas and help are preciated....
I have done an experiment using the good old Northwind Database Suppliers table, modifying your code to suit Here is the code
private void dataGridView1\_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) { if (e.ListChangedType != ListChangedType.ItemDeleted) { DataGridViewCellStyle red = dataGridView1.DefaultCellStyle.Clone(); red.BackColor = Color.LightPink; foreach (DataGridViewRow r in dataGridView1.Rows) { if (r.Cells\["countryDataGridViewTextBoxColumn"\].Value != null) { if (r.Cells\["countryDataGridViewTextBoxColumn"\].Value.ToString() == "USA") { r.DefaultCellStyle = red; } } } } }
It works fine. So your problem probably lies in your
if ((int)r.Cells["nummer6"].Value < 70)
line. You could try something likeif ((int.TryParse(r.Cells["nummer6"].Value.ToString()) < 70)
, although it is a bit of a kludge. I will continue experimenting and will come back to you if I find anything.Henry Minute Do not read medical books! You could die of a misprint. - Mark Twain Girl: (staring) "Why do you need an icy cucumber?" “I want to report a fraud. The government is lying to us all.” Why do programmers often confuse Halloween and Christmas? - Because 31 Oct = 25 Dec. Business Myths of the Geek #4 'What you think matters.'
-
Hi all, I have searched whole day now, for a solution that could fit my needs, yet again, I have to hope that some of your pro's here can help me getting closerto a solution. I'm using DataGridView in C# WinForms to show 6 coloumns (CustomerName, Subscribers, unsubcribed, specialCases, potential, percentage connected in %), it would look like:
CustomerName 20 4 0 24 20/24*100=83%
CustomerName2 12 10 1 22 12/22*100=55%etc. And the rows just continue basedon the number of customers of cause. Now, thats ain't any problem, and I get all my data proper as wanted. Now I want to make it a little bit more useful, and HIGHLIGHT every cell/row with a lightRed color, where the percentage is BELOW 70% (like row number 2 in my example). I have try'd with:
private void grid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemDeleted)
{
DataGridViewCellStyle red = grid.DefaultCellStyle.Clone();
red.BackColor = Color.LightPink;foreach (DataGridViewRow r in grid.Rows) { if ((int)r.Cells\["nummer6"\].Value < 70) { r.DefaultCellStyle = red; } } } }
or with a more similar code:
foreach (DataGridViewRow row in grid.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.ColumnIndex == 5)
{
if ((int)cell.Value < 70)
{
row.DefaultCellStyle.BackColor = Color.LightPink;
}
}
}
}But no matter what, then I can't get the backColor changed on rows where the % value in the last column cell is below 70%. :( Any ideas and help are preciated....
From the experiments that I have done, I can only conclude that the
ValueType
of yournummer6
column is notint
. I would have expected the cast to int to throw an exception, but it doesn't, or at least hasn't in my tests. So, I suggest that you find out the true ValueType of your column and cast it appropriately. One way to do this is to temporarily add the following inside yourforeach
loop, run it once to get the type then delete it.if (r.Index == 0) { MessageBox.Show("Column 6 datatype is " + r.Cells\["nummer6"\].ValueType.ToString()); }
Sorry not to be more help. Good luck! :)
Henry Minute Do not read medical books! You could die of a misprint. - Mark Twain Girl: (staring) "Why do you need an icy cucumber?" “I want to report a fraud. The government is lying to us all.” Why do programmers often confuse Halloween and Christmas? - Because 31 Oct = 25 Dec. Business Myths of the Geek #4 'What you think matters.'
-
From the experiments that I have done, I can only conclude that the
ValueType
of yournummer6
column is notint
. I would have expected the cast to int to throw an exception, but it doesn't, or at least hasn't in my tests. So, I suggest that you find out the true ValueType of your column and cast it appropriately. One way to do this is to temporarily add the following inside yourforeach
loop, run it once to get the type then delete it.if (r.Index == 0) { MessageBox.Show("Column 6 datatype is " + r.Cells\["nummer6"\].ValueType.ToString()); }
Sorry not to be more help. Good luck! :)
Henry Minute Do not read medical books! You could die of a misprint. - Mark Twain Girl: (staring) "Why do you need an icy cucumber?" “I want to report a fraud. The government is lying to us all.” Why do programmers often confuse Halloween and Christmas? - Because 31 Oct = 25 Dec. Business Myths of the Geek #4 'What you think matters.'
Hi there, Thnx for your experimenting, making me a step closer to understand how it work behind. I'm affraid that as you say, the values ain't intergers but strings. I know that the values I have into the cells ARE intergers (count of subscribers in a interger). But seems that the parsing from string to interger won't work. Any ideas? I have decided to show some more source code, since it seems that my _databindingComplete event doesn't even trigger. Sorry for some words in danish (tell me if you need any explained):
public partial class KundeStat_GUI : Form
{
private FrontController Controller = FrontController.Instance;
//private DataGridView grid;private decimal fiberbyTotal\_tilmeldt = 0; private decimal fiberbyTotal\_utilmeldt = 0; private decimal fiberbytotal\_særaftale = 0; private decimal serviceTotal\_tilmeldt = 0; private decimal serviceTotal\_utilmeldt = 0; private decimal serviceTotal\_særaftale = 0; private decimal erhvervTotal\_tilmeldt = 0; private decimal erhvervTotal\_utilmeldt = 0; private decimal erhvervTotal\_særaftale = 0; public KundeStat\_GUI() { InitializeComponent(); } private void KundeStat\_GUI\_Load(object sender, EventArgs e) { Dictionary<string, DataGridView> datas = new Dictionary<string, DataGridView>(); foreach (Kundetype item in Controller.HentAlleKundetyper()) { //grid are specified in KundeStat\_GUI.Designer.cs grid = new DataGridView(); grid.Columns.Add("nummer1", "Foreningsnavn"); grid.Columns.Add("nummer2", "Tilmeldte"); grid.Columns.Add("nummer3", "Ikke tilmeldt"); grid.Columns.Add("nummer4", "Særaftale"); grid.Columns.Add("nummer5", "Potentielle"); grid.Columns.Add("nummer6", "% tilslutning"); grid.Columns\[0\].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; grid.Columns\[1\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[2\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[3\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[4\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[5\].AutoSizeMode = DataGridViewAutoSizeColumnMode.
-
Hi there, Thnx for your experimenting, making me a step closer to understand how it work behind. I'm affraid that as you say, the values ain't intergers but strings. I know that the values I have into the cells ARE intergers (count of subscribers in a interger). But seems that the parsing from string to interger won't work. Any ideas? I have decided to show some more source code, since it seems that my _databindingComplete event doesn't even trigger. Sorry for some words in danish (tell me if you need any explained):
public partial class KundeStat_GUI : Form
{
private FrontController Controller = FrontController.Instance;
//private DataGridView grid;private decimal fiberbyTotal\_tilmeldt = 0; private decimal fiberbyTotal\_utilmeldt = 0; private decimal fiberbytotal\_særaftale = 0; private decimal serviceTotal\_tilmeldt = 0; private decimal serviceTotal\_utilmeldt = 0; private decimal serviceTotal\_særaftale = 0; private decimal erhvervTotal\_tilmeldt = 0; private decimal erhvervTotal\_utilmeldt = 0; private decimal erhvervTotal\_særaftale = 0; public KundeStat\_GUI() { InitializeComponent(); } private void KundeStat\_GUI\_Load(object sender, EventArgs e) { Dictionary<string, DataGridView> datas = new Dictionary<string, DataGridView>(); foreach (Kundetype item in Controller.HentAlleKundetyper()) { //grid are specified in KundeStat\_GUI.Designer.cs grid = new DataGridView(); grid.Columns.Add("nummer1", "Foreningsnavn"); grid.Columns.Add("nummer2", "Tilmeldte"); grid.Columns.Add("nummer3", "Ikke tilmeldt"); grid.Columns.Add("nummer4", "Særaftale"); grid.Columns.Add("nummer5", "Potentielle"); grid.Columns.Add("nummer6", "% tilslutning"); grid.Columns\[0\].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; grid.Columns\[1\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[2\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[3\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[4\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; grid.Columns\[5\].AutoSizeMode = DataGridViewAutoSizeColumnMode.
At the moment I can not see any reason why your
DatabindingComplete
handler doesn't fire. I will continue to look at that though. Even if that was working there are two lines in the code that you posted which are contradictory and may cause problems.grid.Columns\[5\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; **grid.Columns\[5\].ValueType = typeof(decimal);** datas\[item.Kundetype.Type\].Rows.Add(item.KundeNavn, tilmeldte, ikketilmeldt, særaftale, tilmeldte + ikketilmeldt, **procent.ToString("###")**);
In the first block you are setting the
ValueType
toDecimal
and yet in the second you are filling it with a stringprocent.ToString("###")
. This is incompatible. It might be better to modify the last one to simply use the result of your percentage calculation and take care of the displayed data by using theCellFormatting
event of theDataGridView
Like this:datas\[item.Kundetype.Type\].Rows.Add(item.KundeNavn, tilmeldte, ikketilmeldt, særaftale, tilmeldte + ikketilmeldt, procent);
with the CellFormatting handler something like this:
private void grid\_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { // Don't format if cell is null if ((e.Value == DBNull.Value) || (e.Value == null)) { return; } // If it is the 'nummer6' column if (this.dataGridView1.Columns\[e.ColumnIndex\].Name == "nummer6") { // Format data source value and concatenate with " %" string nummer6Format = e.Value.ToString("###") + " %"; // Set the display value e.Value = unitPriceFormat; // Signal that we've Formatted this value e.FormattingApplied = true; //<============================ Very important } }
This way you get to keep a numeric value in the DataGridViewCell/Column, much easier to deal with for comparisons, whilst displaying a prettified version, much easier for humans to deal with. If the
DataFormattingComplete
ever works you can then use yourif ((**decimal**)cell.Value < 70) //<==============
-
At the moment I can not see any reason why your
DatabindingComplete
handler doesn't fire. I will continue to look at that though. Even if that was working there are two lines in the code that you posted which are contradictory and may cause problems.grid.Columns\[5\].AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; **grid.Columns\[5\].ValueType = typeof(decimal);** datas\[item.Kundetype.Type\].Rows.Add(item.KundeNavn, tilmeldte, ikketilmeldt, særaftale, tilmeldte + ikketilmeldt, **procent.ToString("###")**);
In the first block you are setting the
ValueType
toDecimal
and yet in the second you are filling it with a stringprocent.ToString("###")
. This is incompatible. It might be better to modify the last one to simply use the result of your percentage calculation and take care of the displayed data by using theCellFormatting
event of theDataGridView
Like this:datas\[item.Kundetype.Type\].Rows.Add(item.KundeNavn, tilmeldte, ikketilmeldt, særaftale, tilmeldte + ikketilmeldt, procent);
with the CellFormatting handler something like this:
private void grid\_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { // Don't format if cell is null if ((e.Value == DBNull.Value) || (e.Value == null)) { return; } // If it is the 'nummer6' column if (this.dataGridView1.Columns\[e.ColumnIndex\].Name == "nummer6") { // Format data source value and concatenate with " %" string nummer6Format = e.Value.ToString("###") + " %"; // Set the display value e.Value = unitPriceFormat; // Signal that we've Formatted this value e.FormattingApplied = true; //<============================ Very important } }
This way you get to keep a numeric value in the DataGridViewCell/Column, much easier to deal with for comparisons, whilst displaying a prettified version, much easier for humans to deal with. If the
DataFormattingComplete
ever works you can then use yourif ((**decimal**)cell.Value < 70) //<==============
Thnx a lot. I still havn't got it working yet... I'm kinda affraid that its because the dataGridView is "coded" and not drag n' drop'ed... Its just annoying to start over with code who seems too work as they are, but just not when you want this new feature. Its one of my old partners who developed the code, which is why I ain't 100% confident with it yet. If you find an answer why my event ain't triggered, plz let me know (note that this win form has a TabControl and 3 TabPages).