Phil Wright : Component Factory

Wednesday, June 15, 2005

.NET2, Transparent controls

Technical posts start with .NET2

As I have now started coding I intend to feedback any useful technical discoveries as I go along. Hopefully this will help others save a little time in their own projects. You will have noticed the name of the post has .NET2 at the beginning instead of the usual microISV. If your not interested in C# and .NET 2.0 then I guess you would skip these posts.

Rounded corners need to be transparent

Today I came across a tricky problem. I need my control to draw a rounded border inside the edge of the control. This is easy enough to draw, but it does mean that I end up with a small area outside of the border in the wrong color.

Imagine I have a Form with a gradient effect background and then I draw my control. The area outside of the rounded corner is not going to be drawn correctly. It will be the solid BackColor of the control and not the gradient effect of the parent Form.

The obvious solution, and so what I tried first, was to set the BackColor of the control to be Color.Transparent. To make this work you also need to set the control style to be ControlStyles.SupportsTransparentBackColor in the control constructor.

This I duly did and hay presto, it works like a treat. Problem solved, so I move onto another task and think no more about it.

Child controls inherit BackColor

As my control acts like a container, in the same way as a GroupBox does, I was testing it by placing a couple of Button controls inside it. You can probably guess what happened. The Button controls inherit the BackColor from my control and so they now have a transparent background.

This is definitely not a good thing and it looks truly horrific.

So now I am stuck because I need the BackColor to be transparent to let the parent background show through. But I cannot set the BackColor to be transparent because it will be inherited by child controls.

There are only two possible solutions that I can think of. If I assign transparent to the BackColor then I need to detect any child control added and force its BackColor to be a value from the parent of my own control. This sounds a bit tricky to make sure it works in all circumstances.

The alternative is to leave the BackColor property alone but modify my painting routine so it paints as if the property was defined as transparent. This sounds like a much better solution because it localizes the fix in my own code.

So how do we manage to paint the transparent areas?

Reflector

This is where the brilliant Reflector tool written by Lutz Roeder comes in handy. If you have never used it then I suggest you download and install it straight away. It allows you to browse through any assembly, including the framework ones, and decompile the IL code to see how it works.

After snooping around for about 10 minutes I manage to find the code that does the drawing of the background when the background is defined as transparent. Looking at this code it is actually very simple to create my own version that is called from my OnPaint override.

Let me save you the trouble of doing this yourself. Call the following routine to draw the parent over the control when the OnPaint event is overridden.


private void PaintParentBackground(PaintEventArgs e)
{
if (Parent != null)
{
Rectangle rect = new Rectangle(Left, Top,
Width, Height);

e.Graphics.TranslateTransform(-rect.X, -rect.Y);

try
{
using (PaintEventArgs pea =
new PaintEventArgs(e.Graphics, rect))
{
pea.Graphics.SetClip(rect);
InvokePaintBackground(Parent, pea);
InvokePaint(Parent, pea);
}
}
finally
{
e.Graphics.TranslateTransform(rect.X, rect.Y);
}
}
else
{
e.Graphics.FillRectangle(SystemBrushes.Control,
ClientRectangle);
}
}


Victory is mine!

So there you have it. The OnPaint override calls the above routine so that the entire control is initially painted with the appearance of the parent. Then I continue as normal and draw my rounded border, or any other shape I fancy, and the areas I decide not to paint look correct.

1 Comments:

  • I was an avid user of your early .NET UI components when they were free and very impressed with your work. Funny, I've toyed with the same thing you're working on (microISV). I stumbled across your blog this AM and have now read all posts, and can't wait for the next ones!!!
    www.andrewconnell.com

    By Anonymous Anonymous, at 8:16 pm  

Post a Comment

<< Home