views:

1026

answers:

4

Hi !

I'm painting my rows in a DataGridView like this:

private void AdjustColors()
    {            
        foreach (DataGridViewRow row in aufgabenDataGridView.Rows)
        {
            AufgabeStatus status = (AufgabeStatus)Enum.Parse(typeof(AufgabeStatus), (string)row.Cells["StatusColumn"].Value);

            switch (status)
            {
                case (AufgabeStatus.NotStarted):
                    row.DefaultCellStyle.BackColor = Color.LightCyan;
                    break;
                case (AufgabeStatus.InProgress):
                    row.DefaultCellStyle.BackColor = Color.LemonChiffon;
                    break;
                case (AufgabeStatus.Completed):
                    row.DefaultCellStyle.BackColor = Color.PaleGreen;
                    break;
                case (AufgabeStatus.Deferred):
                    row.DefaultCellStyle.BackColor = Color.LightPink;
                    break;
                default:
                    row.DefaultCellStyle.BackColor = Color.White;
                    break;
            }
        }        
    }

Then I call it in the OnLoad method:

protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            AdjustColors();           
        }

I prefer OnLoad to OnPaint or something.. because OnPaint is called very often.

The question: Why does it take about 100 - 200 ms to change the background of every row? Early, I was doint CellPaint.. but I had problems when scrolling with refreshing..

+2  A: 

Its probably the Enum.Parse call, it has poor performance. You should try and change it to a dictionary lookup to see if that improves performance. See this post

SwDevMan81
You are right, that Enum.Parse is slow enough. I rather access the DataBoundItem directly.
PaN1C_Showt1Me
+2  A: 

As SwDevMan1 said, you should first work on removing the Enum.Parse call. Are you using data binding to populate the grid? If so, you can use Rows[index].DataBoundItem to access the data bound object for the row and access the AufgabeStatus status directly.

The second tweak I would suggest is to call SuspendLayout() and ResumeLayout() before and after, respectively, manipulating the grid.

Jamie Ide
PaN1C_Showt1Me
+4  A: 

Instead of changing the color of the whole DataGrid at once, you should let it manage the rendering by overriding the CellFormatting event. The rows will only be painted when they are actually displayed on the screen.

private void aufgabenDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
  DataGridViewRow row = aufgabenDataGridView.Rows[e.RowIndex];
  AufgabeStatus status = (AufgabeStatus) Enum.Parse(typeof(AufgabeStatus), (string) row.Cells["StatusColumn"].Value);

  switch (status)
  {
    case (AufgabeStatus.NotStarted):
      e.CellStyle.BackColor = Color.LightCyan;
      break;
    case (AufgabeStatus.InProgress):
      e.CellStyle.BackColor = Color.LemonChiffon;
      break;
    case (AufgabeStatus.Completed):
      e.CellStyle.BackColor = Color.PaleGreen;
      break;
    case (AufgabeStatus.Deferred):
      e.CellStyle.BackColor = Color.LightPink;
      break;
    default:
      e.CellStyle.BackColor = Color.White;
      break;
  }

}

If this is still too slow, try getting the real object the row is bound to:

...
DataGridViewRow row = aufgabenDataGridView.Rows[e.RowIndex];
var aufgabe = (Aufgabe) row.DataBoundItem;
AufgabeStatus status = aufgabe.Status;
...
Julien Poulin
Well, this solution works seamlessly.
PaN1C_Showt1Me
That could be a proof that I can't handling painting myself but I should rely on the mechanism provided by MS. Now all the rows are recolored immediately !
PaN1C_Showt1Me
And I removed that Enum.Parsing as proposed by ShDevMan
PaN1C_Showt1Me
+1 thanks...I always forget which event to do this in. This will run for each cell correct? I wish there was an event that only fired once per row?
dotjoe
A: 

It's also a good idea to only set the properties if they differ from the expected value. That way you don't trigger unwanted internal DataGridView overhead.

If all cells in a row are formatted the same way, you can do the formatting on row level instead of cell level.

DataGridViewCellStyle rowStyle = row.DefaultCellStyle;
if (rowStyle.BackColor != status.BackColor) { 
   rowStyle.BackColor = status.BackColor;
}
Olivier