Search code examples
.netcompact-frameworkdouble-buffering

.NET CF double-buffering when painting over base control


I've used double-buffering for some .NET Compact Framework controls that are entirely user-drawn, but I'm having trouble figuring out how I can use double-buffering for a control that inherits from another control and paints over it.

I have a control based on DataGrid, that paints over the headers.

My OnPaint method is:

Protected Overrides Sub OnPaint(ByVal pe as System.Windows.Forms.PaintEventArgs)
    MyBase.OnPaint(pe)
    CustomPaintHeaders(pe.Graphics)
End Sub

CustomPaintHeaders just paints on top of the basic DataGrid headers with some custom drawing. Occassionally, I get flickering where I see the basic DataGrid headers get painted, but without my custom-drawn stuff on top.

Is it possible to use double-buffering, and have the painting that's done by MyBase.OnPaint applied to the buffer image?

Edit: As mentioned in my comment, I am able to do double buffering using this code:

Protected Overrides Sub OnPaint(ByVal pe as System.Windows.Forms.PaintEventArgs)
    Using currentRender as Bitmap = New Bitmap(Me.Width, Me.Height)
        Using gr as Graphics = Graphics.FromImage(currentRender)
            CustomPaintHeaders(gr)
            CustomPaintRows(gr)
        End Using
    End Using
End Sub

Private Sub CustomPaintHeaders(ByVal graphics as Graphics)

    'Custom drawing stuff in place of DataGrid column headers

End Sub

'TEMP - draws rectangle in place of grid rows
Private Sub CustomPaintRows(ByVal graphics as Graphics)
    graphics.DrawRectangle(New Pen(Me.ForeColor), 0, 20, Me.Width, Me.Height) 
End Sub

And this works fine without flickering, but I'd like to avoid having to implement CustomPaintRows, and just let DataGrid's OnPaint handle that part for me, and then draw over it's headers with my CustomPaintHeaders method.


Solution

  • Double-buffering in the CF is a manual process, so I would assume that your base class holds an Image or Bitmap onto which it is drawing? It depends on exactly how you're doing your painting but you can either make that Image protected or you can do something slightly more complex like this:

    protected virtual void OnPaint(graphics bufferGraphics) { } 
    
    void OnPaint(PaintEventArgs pe)
    {
        var buffer = new Bitmap(this.Width, this.Height);
        var bufferGraphics = Graphics.FromImage(buffer);
    
        // do base painting here
        bufferGraphics.DrawString(....);
        // etc.
    
        // let any child paint into the buffer
        OnPaint(bufferGraphics);
    
        // paint the buffer to the screen
        pe.Graphics.DrawImage(buffer, 0, 0);
    }
    

    Then in your child, simply override the new OnPaint and do what you want with the incoming Graphics object, which paints onto the buffer, not the screen.

    If you want the child to be able to completely override base painting, just move the base painting logic into the virtual method.