Windows Develop Bookmark and Share   
 index > Windows Forms General > DataGridView & Custom cell painting
 

DataGridView & Custom cell painting

I'm creating a schedule using a datagridview.  The cells in the grid need a lot of special behavour so I created my own Column and Cell classes.  In the Cell.Paint method I draw the cell text in various colors, draw images and lines, depending on data values.

My question is this:  What is the correct order to draw parts of the cell using the DataGridViewPaintParts?  Does it matter?  At present, the display is horrid - sometimes the cells are transparent (I can see what's underneath the application) and the text is scrambled.  A really good example of how to paint a cell would be great!

Thanks

Jonesie  Friday, July 01, 2005 3:47 AM

Painting occurs in the following order:
   1) RowPrePaint
   2) CellPaint
   3) RowPostPaint

The order that CellPaint paints depends upon the cell type, but in general it paints from background to foreground.

One thing that might be misleading is that if you do not let a cell paint at least its background part (DataGridViewPaintParts.Background) then that cell will appear "transparent" or you can see invalidated areas that are not painted (I like to call this a HOM - Hall Of Mirrors effect). This said, it is completely valid to not have the cell paint its background but then you are responsible to paint the background.
 
You can get some really cool looks by customizing the background at the row prepaint level and then not have a cell paint its background. Here is an example:



 private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
 {
     e.PaintParts = DataGridViewPaintParts.ContentForeground;
     Rectangle borderRect = new Rectangle(e.RowBounds.X, e.RowBounds.Y, e.RowBounds.Width - 1, e.RowBounds.Height - 1);

     {
         if ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
         {
             using (LinearGradientBrush lgb = new LinearGradientBrush(e.RowBounds, ProfessionalColors.ToolStripGradientMiddle, ProfessionalColors.ToolStripContentPanelGradientBegin, 90F))
             {
                 using (Pen p = new Pen(ProfessionalColors.ButtonPressedBorder))
                 {
                     e.Graphics.FillRectangle(lgb, borderRect);
                     e.Graphics.DrawRectangle(p, borderRect);
                 }
             }
         }
         else
         {
             using (LinearGradientBrush lgb = new LinearGradientBrush(e.RowBounds, ProfessionalColors.ToolStripContentPanelGradientEnd, ProfessionalColors.ToolStripContentPanelGradientBegin, 0F))
             {
                 e.Graphics.FillRectangle(lgb, e.RowBounds);
             }
         }
     }
 }

 



Hope this helps,
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Friday, July 01, 2005 5:06 AM

Painting occurs in the following order:
   1) RowPrePaint
   2) CellPaint
   3) RowPostPaint

The order that CellPaint paints depends upon the cell type, but in general it paints from background to foreground.

One thing that might be misleading is that if you do not let a cell paint at least its background part (DataGridViewPaintParts.Background) then that cell will appear "transparent" or you can see invalidated areas that are not painted (I like to call this a HOM - Hall Of Mirrors effect). This said, it is completely valid to not have the cell paint its background but then you are responsible to paint the background.
 
You can get some really cool looks by customizing the background at the row prepaint level and then not have a cell paint its background. Here is an example:



 private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
 {
     e.PaintParts = DataGridViewPaintParts.ContentForeground;
     Rectangle borderRect = new Rectangle(e.RowBounds.X, e.RowBounds.Y, e.RowBounds.Width - 1, e.RowBounds.Height - 1);

     {
         if ((e.State & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected)
         {
             using (LinearGradientBrush lgb = new LinearGradientBrush(e.RowBounds, ProfessionalColors.ToolStripGradientMiddle, ProfessionalColors.ToolStripContentPanelGradientBegin, 90F))
             {
                 using (Pen p = new Pen(ProfessionalColors.ButtonPressedBorder))
                 {
                     e.Graphics.FillRectangle(lgb, borderRect);
                     e.Graphics.DrawRectangle(p, borderRect);
                 }
             }
         }
         else
         {
             using (LinearGradientBrush lgb = new LinearGradientBrush(e.RowBounds, ProfessionalColors.ToolStripContentPanelGradientEnd, ProfessionalColors.ToolStripContentPanelGradientBegin, 0F))
             {
                 e.Graphics.FillRectangle(lgb, e.RowBounds);
             }
         }
     }
 }

 



Hope this helps,
-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Friday, July 01, 2005 5:06 AM
That looks promising.  Esentially I just need to draw some images in the background and modifiy the cell text color.  I'll try this out after the weekend. 

Thanks

BTW, great job on the grid.  It's allmost fun to use! :)
Jonesie  Friday, July 01, 2005 5:11 AM

Drawing some images - if it is contained in the cell bounds then you could draw the image using RowPostPaint, or handle CellPainting and first have the cell paint its content then paint your image (use the e.Paint(paintParts.All) available on the CellPainting event args)

Don't forget that with cell styles you can change the font and color of the text without having to custom draw. In addition, cells support padding, so you can add some padding on the left side to provide spacing for your image that you might draw. Padding is another property on the Cell Style.

Thanks for the great comments!

-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Friday, July 01, 2005 5:18 AM
I acheived the desired result by calling the defaullt cell paint event before drawing the images in the cell.  Currently I just need to draw a little triangle in the top right corner of the cell to denote there is an attached note. 

I can see that using the padding will be a good idea to make sure the text is out of the way, but I don't like how the selected cell shows a selection rectangle not including the padding region.... a small complaint.

My next task is to colorize the selected row and column headers to make it more obvious which cells are selected.

Thanks
Jonesie  Sunday, July 03, 2005 11:49 PM

You can use google to search for other answers

Custom Search

More Threads

• Common controls vs all windows forms
• Get a Listing Of Windows Application Forms.
• custom tabPage property problem
• Form Interface Question
• Form get minimized on using show()
• Check if a textbox is selected
• Why System.Windows.Forms.SendKeys.Send("{CAPSLOCK}") is not working?
• displaying text below a thumbnail in a listview, Tile view
• tabcontrol resizing
• I have the same bug as one reported as fixed in MS Connect. How do I find the fix?