Search code examples
c#winforms

Drawing on OnPaint() makes residues when the window is resized


I have created a custom panel that draws a border (that comprises two rectangles). The problem is that if I resize the window, there remain residues... much like the animation of Windows XP's Solitaire. See the screenshot below. I resized the window to the right.

What is wrong, and how can I fix this?

Resized window to the right

protected override void OnPaint(PaintEventArgs e)
{
    var outer = ClientRectangle;
    outer.Width -= 1;
    outer.Height -= 1;
    var inner = outer;
    inner.X++;
    inner.Y++;
    inner.Width -= 2;
    inner.Height -= 2;

    e.Graphics.DrawRectangle(DarkPen, outer);
    e.Graphics.DrawRectangle(WhitePen, inner);

    base.OnPaint(e);
}

UPDATE

At first I thought this was because I did not delete the previously drawn rectangles. So I called FillRectangle to delete the inside.

var contentArea = inner;
contentArea.X++;
contentArea.Y++;
contentArea.Width -= 2;
contentArea.Height -= 2;
e.Graphics.FillRectangle(SystemBrushes.Control, contentArea);

But it did not work either. It seems that the control paints only the newly expanded portion, not the entire area.


Solution

  • The Form class was optimized to be a container control. Containers normally just have a background color to paint. So, as you noticed, indeed does "only paint newly expanded portion". Or more accurately, it does not overpaint the previous pixels, easy to recognize from the smearing effect that produces. It is a somewhat feeble attempt at making Winforms designs a bit more lively when you resize the window, painting gets to be a bottleneck when a form has a lot of controls and that is pretty noticeable.

    You'll have to set its ResizeRedraw property to true so it redraws its entire surface when necessary. Setting the DoubleBuffered property to true might not hurt either when the drawing code gets elaborate and you start noticing flicker.

    So, roughly:

        public Form1() {
            InitializeComponent();
            this.ResizeRedraw = true;
            this.DoubleBuffered = true;
        }
    

    Optimizing OnPaint() is generally not a strategy that pays off, Windows itself already clips what you draw against the dirty region.