Skinned C# form with huge black flicker while resizing!
Asked Answered
G

7

2

I'm trying to create some skinned forms (just the border and caption) with a different approach than you usually see but I'm having some issues with form flickering while I resize the form.

I don't know how else to explain the problem, so here's a video I created to demonstrate the problem: http://www.screencast.com/t/AIqK9Szmz

Also, here's a VS2008 test solution with the whole code that repaints the form borders:http://stuff.nazgulled.net/misc/TestForm.zip

Hope someone can help me get rid of the flicker...

Georgiegeorgina answered 25/11, 2008 at 18:42 Comment(0)
L
2

(This is a Vista-specific solution; it only works when desktop compositing is enabled.)

It looks like Windows initializes the contents of resized forms by copying the pixels on the form's original border over to the new areas. In your case, the new areas are initialized black likely because the form originally had black pixels at its border.

To get rid of the flickering, just keep the rightmost and bottommost line of pixels in the form always set to TransparencyKey -- this will keep the new areas transparent until you get a chance to repaint them. I.e., make the form 1 pixel wider & taller than necessary, and paint the extra pixels transparent.

Example: TransparentForm.zip

Loathly answered 15/3, 2009 at 16:36 Comment(4)
That's a bit confusing for me, can you help me providing an example? It would be nice if you could use the test solution I provided and apply your suggestion cause I'm not sure what to do.Georgiegeorgina
I added an example (your test solution isn't available any more). However, I have since found out that my solution only works under Vista with desktop composition enabled. Under XP and Vista without dwm, you'll still get black flickering.Loathly
I kinda forgot about this, dunno if you are going to see it... But I can't access your example to...Georgiegeorgina
Strange, this only works on Vista with DWM enabled like you said, but I assumed it would be the same in Windows 7 with DWM enabled, but it isn't...Georgiegeorgina
Y
3

That's what I use in my base form's constructor:

this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
this.SetStyle( ControlStyles.UserPaint, true );
this.SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
this.SetStyle( ControlStyles.ResizeRedraw, true );

I think the key is the use of "AllPaintingInWmPaint".

Yurik answered 25/11, 2008 at 18:56 Comment(0)
G
3

If you want to make your form have a irregular shape you will have to turn to regions (if you can easily define your form's region using geometric shapes like Circle and Rectangle). Create a System.Drawing.Graphics.Region object and add shapes to it. I think the property on the form is called Region - assign to it your region that you created.

Your other option is to use layered windows. Somebody has done all the work for you. Layered windows do not work on versions of Windows older than 2000, but they have the added benefit of being semi-transparent.

Your final option is to use WPF and set AllowsTransparency="True" WindowStyle="None". That will remove the chrome (Google "chromeless window WPF" for like a million examples).

Finally if you are brave and patient you could always capture the desktop behind your window and paint it before anything else. You will need to resort to some fancy hackery if your window moves: I don't really recommend this approach - but you need to know all your options.

Glantz answered 26/11, 2008 at 13:34 Comment(0)
L
2

(This is a Vista-specific solution; it only works when desktop compositing is enabled.)

It looks like Windows initializes the contents of resized forms by copying the pixels on the form's original border over to the new areas. In your case, the new areas are initialized black likely because the form originally had black pixels at its border.

To get rid of the flickering, just keep the rightmost and bottommost line of pixels in the form always set to TransparencyKey -- this will keep the new areas transparent until you get a chance to repaint them. I.e., make the form 1 pixel wider & taller than necessary, and paint the extra pixels transparent.

Example: TransparentForm.zip

Loathly answered 15/3, 2009 at 16:36 Comment(4)
That's a bit confusing for me, can you help me providing an example? It would be nice if you could use the test solution I provided and apply your suggestion cause I'm not sure what to do.Georgiegeorgina
I added an example (your test solution isn't available any more). However, I have since found out that my solution only works under Vista with desktop composition enabled. Under XP and Vista without dwm, you'll still get black flickering.Loathly
I kinda forgot about this, dunno if you are going to see it... But I can't access your example to...Georgiegeorgina
Strange, this only works on Vista with DWM enabled like you said, but I assumed it would be the same in Windows 7 with DWM enabled, but it isn't...Georgiegeorgina
M
1

You'll have to give up on using the Form.TransparencyKey property if you want to avoid the ugly uninitialized black video overlay flicker. It doesn't do anything useful in your sample program.

Morse answered 26/11, 2008 at 12:32 Comment(0)
A
0

Tried enabling DoubleBuffering ?

Auteur answered 26/11, 2008 at 13:0 Comment(0)
G
0

Oh, and by the way, using SLIMcode's code won't work unless you put all your paint logic in override OnPaint(). If this doesn't sound familiar you probably don't know that you can forcefully ask for a repaint by calling Invalidate() on your form. It's a mission to refactor your code into a single Paint method - but it results in cleaner code in the end.

Glantz answered 26/11, 2008 at 13:38 Comment(1)
This being said, I am not sure if putting all the logic in OnPaint() will fix the flicker.Glantz
D
0

To get rid of the flicker while resizing the win form, suspend the layout while resizing. Override the forms resizebegin/resizeend methods as below.

protected override void OnResizeBegin(EventArgs e) {
    SuspendLayout();
    base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
    ResumeLayout();
    base.OnResizeEnd(e);
}

This will leave the controls intact (as they where before resizing) and force a redraw when the resize operation is completed.

Diplomatics answered 13/10, 2011 at 20:23 Comment(1)
It didn't fix the problem and I don't like the fact that the controls remain intact.Georgiegeorgina

© 2022 - 2024 — McMap. All rights reserved.