I'm making a .NET 3.5 app with a form that draws a partially transparent black background. I'm overriding OnPaintBackground to accomplish this:
protected override void OnPaintBackground( PaintEventArgs e )
{
using ( Brush brush = new SolidBrush( Color.FromArgb( 155, Color.Black ) ) )
{
e.Graphics.FillRectangle( brush, e.ClipRectangle );
}
}
It works, but occasionally the form draws over itself without clearing the screen, making the transparency darker than it should be. I've tried playing with Graphics.Flush()
and Graphics.Clear()
, but it either doesn't help or completely removes transparency. Any suggestions?
Edit: Here's what it looks like, after starting the app on the left, and after the form redraws itself a few times (in response to tabbing from one control to another) on the right:
Transparency Issue http://www.quicksnapper.com/files/5085/17725729384A10347269148_m.png
Edit 2: I was trying a few things out this morning and noticed that when the desktop behind the transparent portions change, it's not actually being redrawn. For example, if I open Task Manager and put it behind the window, you don't see it refreshing itself. This makes sense with what I've been seeing with the transparency levels. Is there a function to make Windows redraw the area behind your window?
Edit 3: I've tried changing a few properties on the form, but they all result in the form drawing non-transparent black:
this.AllowTransparency = true;
this.DoubleBuffered = true;
this.Opacity = .99;
I'm going to try creating a separate window for the transparent portion as overslacked mentioned, but any other ideas are still welcome.
Is
Graphics.CompositingMode
set toCompositingMode.SourceCopy
? That should cause painting the background twice to be equivalent to painting it once, since it will replace the existing alpha/color data instead of compositing over it.I think I would call this expected behavior, actually. What I would do is render my background to an in-memory bitmap and, in the paint event, copy that to the form (basic double-buffering).
If I'm way off base, could you post a screenshot? I don't know that I'm imagining what you're describing correctly.
EDIT:
I'm wondering about your use of OnPaintBackground... pre-.NET, if you were doing double-buffering you'd catch and ignore the WM_ERASKBKGND message (to prevent flicker), render your image to an offscreen buffer, and copy from the buffer to the screen on WM_PAINT. So, try changing from the OnPaintBackground to OnPaint.
I haven't done too much of this kind of thing in .NET, but I had a pretty good handle on it before; I just don't know if it'll translate well or not!
EDIT 2:
Marc, the more I think about what you're trying to do, the more problems appear. I was going to suggest creating a background thread dedicated to capturing the screen and rendering it darkened; however, in order to remove your own form you'd have to set the visibility to false which would create other problems....
If you're unwilling to give up, I would suggest creating two windows and "binding" them together. Create a semi-opaque window (by setting opacity) for your background window, and create a second "normal" window for the foreground. Use SetWindowRgn on the foreground window to cut away the background and position them on top of each other.
Good luck!