views:

3831

answers:

11

Hi, 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...

+3  A: 

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".

Martin Plante
A: 

That's exactly what I use in my code that I posted above but it doesn't solve the issue :(

Nazgulled
a response to a reply should be a comment on that reply, not a new response. They are not ordered like in a regular forum.
Neil N
+1  A: 

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.

Hans Passant
A: 

How do you suggest I make the form transparent then? Besides skinning the form, I need it to have an irregular shape... The example I posted may not have been the best example because the corners are square, but that was just a not well though example because like I said, I need to have transparency for irregular shaped forms.

Nazgulled
A: 

Tried enabling DoubleBuffering ?

sindre j
A: 

If you are refering to the form property, then yes.

Nazgulled
+2  A: 

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.

Jonathan C Dickinson
A: 

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.

Jonathan C Dickinson
This being said, I am not sure if putting all the logic in OnPaint() will fix the flicker.
Jonathan C Dickinson
A: 

Maybe regions is my only option, although, some said to me that if my form used the opacity property (which it does, depending on the user setting for the application), the black flicker would still be a problem. My problem with regions is that I want to turn my code into a library and it will be harder to make it like this instead of simply providing a background image.

Layered Windows is not an option since it doesn't fully support lots of Windows Forms controls to be added to the form itself and this is very important for my application. The last example on this page shows exactly what I wanted to achieve if I were to use Layered Windows but it has some compatibility problems.

WPF is also not an option for now... That was my first choice long a time ago, but since the ClearType rendering in WPF is much worse (ugly) than the Windows Forms one I don't want to use. I hate text rendered by WPF, that's what's holding me back from WPF applications.

My current painting is done on OnBackgroundPaint(), it's basically the same as OnPaint (sort of).

Nazgulled
+2  A: 

(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

Fnord
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.
Nazgulled
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.
Fnord
I kinda forgot about this, dunno if you are going to see it... But I can't access your example to...
Nazgulled
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...
Nazgulled
A: 

Use above code in constructor. and suspend layout before writing this..

I'm not sure what you mean, can you be a little more specific?
Nazgulled