Introduction
.NET Compact Framework doesn't provide out-of-box controls with transparent background. This article shows how to create user controls to overcome this issue.
Background
In a recent .NET compact framework application I was working on, I needed to add an image to the form's background. I did it by using the code from this video tutorial from Microsoft. However, the video also told us that the label control (and other controls) in .NET compact framework doesn't support transparent background. You will have to create your own user control. I found a good article Creating gradient background with transparent labels in .NET Compact Framework by Per Ola Sæther. It helped me to create my solution.
Using the Code
The basic ideas to create a transparent control is to override the OnPaintBackgound
method of the control so it calls the parent form's OnPaintBackgound
to draw the background and then draw content of the control on top of it.
In that article, the author showed how to create a transparent label control. But the code can be simplified. I also did some refactoring work so it extends to not just label control.
First, I created the same interface introduced in that article.
public interface IPaintControl
{
void InvokePaintBackground(PaintEventArgs e);
}
Then I created a base form so I don't have to write the same code for each form.
public class CcForm : Form, IPaintControl
{
public virtual void InvokePaintBackground(PaintEventArgs e)
{
OnPaintBackground(e);
}
}
A base control is created so we can have not only the transparent label, but also other kinds of controls, such as radio button and checkbox. It has a property called TransparentBackground
. If you don't want your control to be transparent for some reason, you can change this property. In the OnPaintBackground
method, it calls its parent’s InvokePaintBackground
to draw the background.
public class CcTransparentControl : Control
{
private bool _transparentBackgound = true;
public bool TransparentBackground
{
get
{
return _transparentBackgound;
}
set
{
_transparentBackgound = value;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
if (_transparentBackgound)
{
IPaintControl parent = Parent as IPaintControl;
if (parent != null)
{
parent.InvokePaintBackground(e);
}
}
else base.OnPaintBackground(e);
}
}
Now we can create the transparent label control using the following code:
public class CcTransparentLabel : CcTransparentControl
{
private ContentAlignment textAlign = ContentAlignment.TopLeft;
public ContentAlignment TextAlign
{
get
{
return textAlign;
}
set
{
textAlign = value;
}
}
public CcTransparentLabel()
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics gfx = e.Graphics;
if (this.TextAlign == ContentAlignment.TopLeft)
{
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), ClientRectangle);
}
else if (this.TextAlign == ContentAlignment.TopCenter)
{
SizeF size = gfx.MeasureString(this.Text, this.Font);
int left = this.Width / 2 - (int)size.Width / 2;
var rect = new Rectangle(ClientRectangle.Left + left,
ClientRectangle.Top, (int)size.Width,
ClientRectangle.Height);
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), rect);
}
else if (this.TextAlign == ContentAlignment.TopRight)
{
SizeF size = gfx.MeasureString(this.Text, this.Font);
int left = this.Width - (int)size.Width + this.Left;
var rect = new Rectangle(ClientRectangle.Left + left,
ClientRectangle.Top, (int)size.Width,
ClientRectangle.Height);
gfx.DrawString(this.Text, this.Font,
new SolidBrush(this.ForeColor), rect);
}
}
}
In our form, we change the form to inherit from CcForm
and drag/drop a CcTransparentLabel
onto it.
public partial class FormWithSolidColorBackground : CcForm
Here is the screen shot. As you can see, the label has transparent background now.
However, when I tried to add image background with gradient color, my label doesn't look right anymore.
To understand the issue, we need to first take a look at how we display background image on a form.
public partial class FormWithImageBackground : CcForm
{
private Rectangle _backgroundRect;
private Bitmap _background;
private string currentPath = Path.GetDirectoryName
(Assembly.GetExecutingAssembly().GetName().CodeBase.ToString());
public FormWithImageBackground()
{
InitializeComponent();
_background = new Bitmap(currentPath + @"\ImageBackground.jpg");
_backgroundRect = new Rectangle(0, 0, _background.Width, _background.Height);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(_background, this.ClientRectangle,
_backgroundRect, GraphicsUnit.Pixel);
}
}
What happened is when the OnPaintBackground
was called by the transparent label control, it re-draws the image inside of the label control. So it shows the top-left corner of the image on the label’s background. To fix this issue, I pass in the location of the label control to the form and use it to re-draw the image. For example, if the label is located at (10, 20), the image background would be displayed at (-10, –20). This may not be the best solution, but it is simple and it worked. Here is the revised interface and controls.
public interface IPaintControl
{
void InvokePaintBackground(PaintEventArgs e, Point location);
}
public class CcForm : Form, IPaintControl
{
public virtual void InvokePaintBackground(PaintEventArgs e, Point location)
{
OnPaintBackground(e);
}
}
public class CcTransparentControl : Control
{
....
protected override void OnPaintBackground(PaintEventArgs e)
{
if (_transparentBackgound)
{
IPaintControl parent = Parent as IPaintControl;
if (parent != null)
{
parent.InvokePaintBackground(e, this.Location);
}
}
else base.OnPaintBackground(e);
}
}
In the form, I then override the InvokePaintBackground
method to draw the image at the desired location.
public override void InvokePaintBackground
(System.Windows.Forms.PaintEventArgs e, System.Drawing.Point location)
{
Graphics g = e.Graphics;
Rectangle destRect = new Rectangle(-1 * location.X, -1 * location.Y,
ClientRectangle.Width, ClientRectangle.Height);
g.DrawImage(_background, destRect, _backgroundRect, GraphicsUnit.Pixel);
}
Now we have a transparent label over image background.
I also created a transparent radio button and checkbox controls. These are the controls commonly used in a form and so is the Panel
control. The following example showed the transparent radio button and checkbox on a transparent panel.
Happy programming!
History
- 8th October, 2009: Initial post
- 9th October, 2009: Article updated