preload
May 05

A few days ago I wanted to create a fresher UI then what .NET Compact Framework offers out of the box. I wanted to create a gradient background for the screen and I wanted to have transparent labels on top of the background. In my opinion this is not much to ask for and I was a bit surprised that I actually had to do this myself.

Well after a few hours I made a gradient background and a transparent label. I will now step by step go through my solution.

The first thing I started with was to create a gradient background. I found that the best way achieving this would be to override OnPaintBackground in the Screen class. I found a very good article on how to do this on MSDN: How to display a gradient fill. I copied the GradientFill class and the Win32Helper class into my project, I didn’t bother using the GradientFilledButton class since I only needed gradient for my background.

Then I override the OnPaintBackground in my Screen, giving me this Form:

using System.Drawing;
using System.Windows.Forms;

<span id="more-601"></span>

namespace GradientTransparentTest
{
    public partial class GradientTransparentForm : Form
    {
        public GradientTransparentForm()
        {
            InitializeComponent();
        }

        // Paints the background of the form with a GradientFill pattern.
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            GradientFill.Fill(
            e.Graphics, ClientRectangle,
            Color.Silver, Color.LightBlue,
            GradientFill.FillDirection.LeftToRight);
            e.Graphics.Dispose();
        }
    }
}

This is what my simple Form with Gradient background looks like

gradient background

OK, we now have a gradient background without having to do too much work. Lets have a look at how we can create a transparent label to put on top of our gradient background.

I created a TransparentLabel.cs which extends Control and uses the original Label control. This means that you can add a label in the designer and give it the needed properties and set it to visible=false. TransparentLabel will use the properties from the Label in OnPaint.

This is what my TransparentLabel.cs looks like now:

using System.Drawing;
using System.Windows.Forms;

namespace GradientTransparentTest
{
    public class TransparentLabel : Control
    {
        private Label label;

        public TransparentLabel(Label label)
        {
            this.label = label;
            Bounds = label.Bounds;
            Location = label.Location;
            ClientSize = label.ClientSize;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics gfx = e.Graphics;
            if (label.TextAlign == ContentAlignment.TopLeft)
            {
                gfx.DrawString(label.Text, label.Font, 
                new SolidBrush(label.ForeColor), ClientRectangle);
            }
            else if (label.TextAlign == ContentAlignment.TopCenter)
            {
                SizeF size = gfx.MeasureString(label.Text, label.Font);
                int left = label.Width/2 - (int) size.Width/2;
                var rect = new Rectangle(ClientRectangle.Left + left,
                ClientRectangle.Top, (int) size.Width,
                ClientRectangle.Height);
                gfx.DrawString(label.Text, label.Font,
                new SolidBrush(label.ForeColor), rect);
            }
            else if (label.TextAlign == ContentAlignment.TopRight)
            {
                SizeF size = gfx.MeasureString(label.Text, label.Font);
                int left = label.Width - (int) size.Width + label.Left;
                var rect = new Rectangle(ClientRectangle.Left + left,
                ClientRectangle.Top, (int) size.Width,
                ClientRectangle.Height);
                gfx.DrawString(label.Text, label.Font,
                new SolidBrush(label.ForeColor), rect);
            }
        }

        // Override this method with no code
        // to enable transparent background
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }
    }
}

Then you add a original Label to your Form by using the designer. Remember to set the Label to visible=true. You now need to create the TransparentLabel with the Label as a parameter in your Form. I added the code below in the constructor right after InitializeComponents() in my GradientTransparentForm.cs

TransparentLabel transparentLabel = new TransparentLabel(lbTransparent);
Controls.Add(transparentLabel);

I was happy with my code and ran the application, but do you know what? The TransparentLabel had become a bit too much transparent. When overriding the OnPaintBackground with no code the gradient background was not drawn under where I had placed my TransparentLabel. I tried to Invalidate, Update and Refresh the background, but it still didn’t work

You can see that in the area I placed my TransparentLabel the time from my OS home screen are showing

transparent label

Bummer! I still had some work left. I found that I actually had to Invoke the OnPaintBackground (the gradient drawing). So I made a simple Interface called IPaintControl. I found the tips about invoking OnPaintBackground from the MSDN forum were Michael Koster (MVP) showed an example on this.

using System.Windows.Forms;

namespace GradientTransparentTest
{

    // External paint control interface
    public interface IPaintControl
    {
        // have the foreground painted
        void InvokePaint(PaintEventArgs e);

        // have the background painted
        void InvokePaintBackground(PaintEventArgs e);
    }
}

Then I implemented IPaintControl in GradientTransparentForm and added the two required methods.

public partial class GradientTransparentForm : Form, IPaintControl
.
.
.
    public void InvokePaint(PaintEventArgs e)
    {
        OnPaint(e);
    }

    public void InvokePaintBackground(PaintEventArgs e)
    {
        OnPaintBackground(e);
    }

In TransparentLabel I will now force drawing of the Form background in OnPaintBackground using the IPaintControl interface

// Override this method invoking the parents' OnPaintBackground
// to enable transparent background
protected override void OnPaintBackground(PaintEventArgs e)
{
    IPaintControl parent = (IPaintControl)Parent;
    if (parent != null)
    {
        parent.InvokePaintBackground(e);
    }
}

Finally I had my transparent label, looking like this:transparent label2

I don’t know if this is the easiest way to do this, but it works great for me. I will now continue developing my application, happily using gradient and transparent labels :)

You can download my GradientTransparentTest project with all the source code needed. Click here to get the project as a .zip file (Visual Studio 2008 project)

Follow me on twitter @PerOla

Share & enjoy
You can subscribe to my comments feed to keep track of new comments.

18 Comments to “Creating gradient background with transparent labels in .NET Compact Framework”

  1. Hiren says:

    Thanks. It helps me lot.

  2. Hiren,
    I’m glad you found this useful.

  3. Bjorn says:

    Thanks for sharing your code. I’m currently working on a application for WM, and I will use your lines when creating my gradients. I hope this isn’t any problem. Thanks again.

  4. Bjorn: Feel free to use any code lines you find on this blog as if they were your own. Good luck on your WM app :)

  5. VJ says:

    Very good, was searching for this stuff since last two weeks. Thanks for sharing the article as well as code.

  6. Mark Read says:

    Nice bit of code. However it doesnt work if you have your gradient fill TopToBottom (as opposed to LeftToRight, this is because it will fill the label based on the colors at the top of the screen, hence if the lable is lower down the screen the background doesnt look transparent. Any ideas how to solve this ?

  7. Hi Mark.
    I understand your problem since this code example is more to be consider a conceptual example on how this can be achieved. The TransparentLabel.cs is invoking the OnPaintBackground in GradientTransparentTest.cs
    As you can see the OnPaintBackground is hardcoded with the gradient start color (silver) and the gradient end color (blue) and this causes your label to be filled with a gradient color not consistent to the gradient background. One way to solve this would be to calculate the exact color your background has at the start Y-position for the label.

    I might write a more sophisticated example covering this issue in the near future.

  8. Alaa Ezzat says:

    Very Nice Sir , Helps A Lot

    and let me add , that if you are packadging your code and don’t want the user to have to implement the IPaintControl you can use reflection , a bit slower , but works in default scenario with no tweaks , like :

    protected override void OnPaintBackground(PaintEventArgs e)
    {
    System.Reflection.MethodInfo method = Parent.GetType().GetMethod(“OnPaintBackground”, BindingFlags.Instance | BindingFlags.NonPublic);

    method.Invoke(Parent,new object[]{ e});

    }

  9. Hi Alaa Ezzat,

    Thanks for your comment and I like your example on using reflection to Invoke the parent OnPaintBackground.

  10. mzoy says:

    Thanks!

  11. Ajit Nagar says:

    hello,
    This is really nice one.
    but i got the error of importing the dll named coredll in win32helper class.
    so how could you find this dll?

  12. Hi Ajit Nagar,
    The Coredll.dll is a part of Windows CE/Mobile and is in the ROM. You will not find Coredll.dll on your disk.

    You will typically get this error if you try to run device code on desktop.

  13. Arathi says:

    Hi,
    I am facing problem while creating the transparent labels. I am doing this in Vb.net.
    I followed the instructions till adding the TransparentLabel.vb and couldn’t go further in improving the looks of TransparentLabel. After that, i built the application, and could get the Transparent label in the toolbox but while putting the control on the form, it gives an big error message saying ‘Failed to create component ‘TransparentLabel’. The error message follows:
    ‘System.MissingMethodException: Constructor on typw ‘GRADIENT.TransparentLabel’ not found.
    at System.RuntimeType.CreateInstanceImp(BindingFlags bindingAttr, Binder binder,Object[] args,CultureInfo culture,Object[] activationAttributes)
    ….
    ….

    Please let me know where i have gone wrong.

  14. Arathi,
    I’m not sure where you have gone wrong. The code example above works on .NET Compact Framework. I have not done any Vb.net coding so I am not sure if you can use this example directly in VB.

    If I understand you correct you get the error when you are using the visual designer. Try to add the TransparentLabel manually without using the visual designer. You can also have a look at an article I wrote about how to code your user controls so that they can be used by the visual designer: http://breathingtech.com/2009/using-user-controls-with-external-dll-references-in-visual-studio-designer/

  15. RAHUL says:

    Instead form i want to place transparent label on gradientfill panel.Panel is gradient filled using paintbackground event but label does not dislay any text on panel.

  16. Aymen says:

    Hi I did exactly same steps but it did’nt work, I’m using an image in the background can this cause the difference ???

  17. swarovski says:

    It is actually a great and useful piece of information.
    I am satisfied that you shared this useful information with us.
    Please stay us informed like this. Thanks for sharing.

1 Pingback to “Creating gradient background with transparent labels in .NET Compact Framework”

  1. [...] have earlier written a post about Creating gradient background with transparent labels in .NET Compact Framework and the approach when creating a gradient button is quite similar. As a base for drawing gradient I [...]

Leave a Reply

Subscribe to my comments feed

Subscribe to my feeds Follow me on Twitter
DZone MVB