Click here to Skip to main content
Click here to Skip to main content

Creating Transparent Controls in .NET Compact Framework

By , 9 Oct 2009
 

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
{
    // have the background painted
    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
{
    // have the background painted
    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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

DotNetIdeas
Team Leader www.dotnetideas.com
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionBetter LabelmemberDaniel Romero19 Oct '12 - 4:29 
The DrawString used in this article was printing text at a single line, not wraping around the ClientRetangle. After messing around trying to write my own wrap function, I found out if you use DrawString that uses Retanglef does this automatcally. Here it goes:
 
gfx.DrawString(this.Text, this.Font,
                new SolidBrush(this.ForeColor), new RectangleF((float)this.ClientRectangle.Left, (float)this.ClientRectangle.Top, (float)this.ClientRectangle.Width, (float)this.ClientRectangle.Bottom));

Questioni want to create tabcontrolmembersherif4c_sharp25 Apr '11 - 4:35 
Dears,
 
I want to create tabcontrol like panel with transparent background but the function "onpaintbackground" not called how i can do that?
sherif

GeneralMy vote of 3memberdriffter3 Nov '10 - 1:56 
Very good code, but poor explanation
QuestionExcese me , I want know something about panel,can you help me?memberlrt_no121 Jan '10 - 19:23 
First thanks for your TransparentControl,I know much.
I am sorry about my english.
there is a question about TranspatentPanel.
I know it is transpatent.but when something in it,like this:
" this.ccTransparentPanel1.Controls.Add(this.ccTransparentLabel12);
this.ccTransparentPanel1.Controls.Add(this.ccTransparentLabel11);"
and this.ccTransparentPanel1.AutoScroll = true;
when I drag it .Panel is not smooth.
can you understand me?
I want to talk about this.
My email: lrt@phoneos.org
AnswerRe: Excese me , I want know something about panel,can you help me?memberDotNetIdeas22 Jan '10 - 6:02 
Do you mean when you scroll it, the panel flicks? That is the limitation of this method. Because they are not true transparent controls. We just re-paint their parent's background to make they look like transparent.
GeneralRe: Excese me , I want know something about panel,can you help me?memberlrt_no122 Jan '10 - 15:22 
Thank you,I kewn it.But how can I make a really Transparent panel .
You know there are many controls we want to join in a panel,and moving it with the panel.If the panel can not transparent,smothing under the panel can not be see.
It is a big problem to me,when the panel is moving,others in it will onpain,
If useing "double buffer" can resolve it?
But I don't konw how to rewrite your transparent panel with double buffer.
GeneralRe: Excese me , I want know something about panel,can you help me?memberDotNetIdeas23 Jan '10 - 15:23 
I can't think of an esay way to solve this issue. Maybe you need to try a diffenrent approach. Check this
http://www.codeplex.com/alphamobilecontrols[^] site. Hope it helps.
GeneralRe: Excese me , I want know something about panel,can you help me?memberlrt_no124 Jan '10 - 21:15 
Thanks for your help
GeneralWant to draw transparent control on top of a labelmembertelll_me_morely23 Oct '09 - 9:43 
Hi,
I am new to .net. I want to draw a transparent panel (with X mark on it)on top of a label. My application works fine. The X lines appear on the label except where the label text is. There is a discontinuity in the lines where the text is. How do I paint on top of the label text?
 
Thanks in advance
GeneralRe: Want to draw transparent control on top of a labelmemberDotNetIdeas27 Oct '09 - 9:34 
Well, the easiest way to work around the issue would be forget about the label. Just paint the string on the transparent panel directly and then paint the X.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 9 Oct 2009
Article Copyright 2009 by DotNetIdeas
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid