True Transparency Support for the .NET CheckBox Control






3.64/5 (22 votes)
An article on adding true transparency support to the .NET CheckBox control, in C# or VB.NET
Introduction
There are several articles on the web bemoaning the failure of the .NET Tab
control to Theme properly. Some of these mention that the CheckBox
control, among others, does not draw its background correctly when used on the tab control. The core of the problem for the checkbox
is that it does not properly support transparency.
This article addresses this issue and adds transparency support to the CheckBox
control. Additionally, it makes the control draw in XP Style, when the FlatStyle
is set to FlatStyle.Standard
, even on older platforms that don't support themes.
Reproducing the Problem
The problem itself is easy to reproduce. While there is no problem using transparency on the CheckBox
in simple applications, as soon as you start to control painting of controls yourself, for example, to add a gradient fill to a form, the problems begin! See for yourself.
Create a new Windows Application Project and drop the standard .NET CheckBox
onto the Form1
that Visual Studio creates for you.
Now, add the following code to give the form a gradient filled background:
protected override void OnPaintBackground(
System.Windows.Forms.PaintEventArgs e)
{
base.OnPaintBackground(e);
System.Drawing.Drawing2D.LinearGradientBrush brush
= new System.Drawing.Drawing2D.LinearGradientBrush(
this.ClientRectangle,
System.Drawing.SystemColors.Highlight,
System.Drawing.SystemColors.Window,
System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
e.Graphics.FillRectangle(brush, this.ClientRectangle);
brush.Dispose();
}
Protected Overrides Sub OnPaintBackground( _
ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(e)
Dim brush As New System.Drawing.Drawing2D.LinearGradientBrush( _
Me.ClientRectangle, _
System.Drawing.SystemColors.Highlight, _
System.Drawing.SystemColors.Window, _
System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal)
e.Graphics.FillRectangle(brush, Me.ClientRectangle)
brush.Dispose()
End Sub
As you can see, the CheckBox
picks up the BackColor
of the control behind it, in this case the Form
, and not the gradient fill you painted. You can't remedy this by setting the BackColor
to Transparent
as the control does not support it.
The Solution, Stage 1
At first, all seemed easy. If you subclass the CheckBox
control and set the SupportsTransparentBackColor
style bit to true
, it becomes possible to set the BackColor
to Transparent
and all seems fine. The subclass looks like this:
public class MyCheckBox : CheckBox
{
public MyCheckBox(): base()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
}
Public Class MyCheckBox : Inherits CheckBox
Public Sub New()
MyBase.New()
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
End Sub
End Class
A few quick tests, changing the FlatStyle
proves this to work fine for FlatStyle.Flat
, FlatStyle.Popup
and FlatStyle.Standard
, but FlatStyle.System
now displays a white background, even with themes enabled!
This may be sufficient for many of you, but the next stage deals with this problem as well.
The Final Solution
In the end, the only solution proved to lie in taking over the drawing of the check mark completely. It was necessary to hide the FlatStyle
from the base class, and when it appears to be set to FlatStyle.System
, set the base class property to FlatStyle.Standard
and subvert the painting of the control. In fact, the standard check mark does draw underneath, but my custom check mark draws over the top.
In keeping with the way in which the .NET CheckBox
control manages its drawing, I created a helper class to draw the check mark in a specified position. The colors are then provided by a third class that supplies the correct color set for the current theme by calling the Windows uxTheme.Dll to find out what the current theme is. If themes are not supported (Pre Windows XP), the color class returns the Blue theme colors, so you could use this to give your non themed apps the themed look and feel.
One side effect of calling the uxTheme.dll is that the UnManaged Code Access Security permission is required. Thankfully, I was able to avoid a stack walk at run time, however, the permission is required at JIT compile time. Normally, this is not an issue. However, you will find that you cannot use this control from a network share without fiddling with your .NET Security Configuration. However, this is the same problem you would have if you tried to use any other control set from a network share as all the decent ones call Unmanaged code at some point, and in fact, so many things are not possible in this configuration that it is advisable to run all .NET apps from a local drive.
On the plus side, my control actually themes better than the default .NET CheckBox
control, as the color of the check mark border does not vary with the themes in the .NET control, whereas my control sets the check mark border to the same color as the font color used in the expander panel headers of the Explorer bar shown on the left of the My Computer view of Windows Explorer. I chose this as the colors match for the default (Blue) theme and I think it is an improvement.
Aside from defaulting the BackColor
to Transparent
, and the FlatStyle
to FlatStyle.System
, I have made no changes to the default action of this customization of the CheckBox
control. In my personal version, I have defaulted the text to an empty string, forced the DataBinding
s to persist in the designer, and added a databinding between the checked state and the font style so that the text changes to bold font when the CheckBox
is checked.
Please note that the control does not provide a view through to the windows behind when using the Form
, TransparencyKey
property. This is because I have had to set the AllPaintingInWMPaint
style bit to true
to ensure that the check mark draws correctly.
Using the Control
The demo project and source code differ only in the inclusion of a Windows application project to demonstrate the difference between the CustomCheckBox
and the default CheckBox
. Both zip files contain the entire source code for the three classes required, packaged as Windows Control Projects in C#.NET and VB.NET so that you can copy the source code into your own projects.
If you wish to use the control as it is, build either Windows control project, C#.NET or VB.NET as your preference takes you, and add the control to your toolbox by selecting the resulting assembly from the Add/Remove Items dialog when customizing your Toolbox.
History
- 25th September, 2004: Initial version