Creating transparent Windows Forms controls.

 

The transparency feature of the Windows Forms control leaves much to be desired and is a blatant fudge. The control is not really transparent, it just pretends to be by looking at the background of it's parent control and copying the appropriate portion of the image or background onto it's own surface during the OnPaintBackground method.

 

This means that a "transparent" control placed on top of another on the same parent will in fact obscure the other child controls. Figure 1 shows this effect in action.

 

Figure1: A supposedly transparent Panel

 

The panel control to the right of the form obscures the PictureBox control and shows only the background of the parent.

 

In order to make a truly transparent control we need to do a couple of things. Firstly, it's necessary to change the behaviour of the window by giving it a WS_EX_TRANSPARENT style. This is accomplished by overriding the CreateParams property so that the correct window style is included when the control is instantiated. The listing below shows this property override.

 

protected override CreateParams CreateParams

{

  get

  {

    CreateParams cp=base.CreateParams;

    cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT

    return cp;

  }

}

 

The second thing we need to do is to invalidate the parent of the control, not the control itself, whenever we need to update the graphics. This ensures that whatever is behind the control gets painted before we need to do our own graphics output. To do this, a routine such as that shown in the following listing is needed.

 

protected void InvalidateEx()

{

  if(Parent==null)

    return;

  Rectangle rc=new Rectangle(this.Location,this.Size);

  Parent.Invalidate(rc,true);

}

 

Finally, we need to ensure that the background draw routine does not mess up the recently repainted parent-form content by stubbing out the OnPaintBackground method.

 

protected override void OnPaintBackground(PaintEventArgs pevent)

{

  //do not allow the background to be painted 

}

 

Now the control is ready for the rest of its modification. It is important to note at this point that transparent controls are not suitable for double buffering using the standard SetStyle method. The memory bitmap which is provided to your code has an opaque background and does not allow the carefully retained parent pixels to show through.

 

To complete this article, a simple control that does nothing but paint moving ellipses on its surface is shown in the following listing.

 

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 

 

namespace transcontroldemo

{

  /// <summary>

  /// Summary description for TransPanel.

  /// </summary>

  public class TransPanel : Panel

  {

 

    Timer Wriggler=new Timer();

 

    public TransPanel()

    {

      //

      // TODO: Add constructor logic here

      //

 

      Wriggler.Tick+=new EventHandler(TickHandler);

      this.Wriggler.Interval=500;

      this.Wriggler.Enabled=true;

    }

 

    protected void TickHandler(object sender, EventArgs e)

    {

      this.InvalidateEx();

    } 

 

    protected override CreateParams CreateParams

    {

      get

      {

        CreateParams cp=base.CreateParams;

        cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT

        return cp;

      }

    }

 

    protected void InvalidateEx()

    {

      if(Parent==null)

        return;

 

      Rectangle rc=new Rectangle(this.Location,this.Size);

      Parent.Invalidate(rc,true);

    }

 

    protected override void OnPaintBackground(PaintEventArgs pevent)

    {

      //do not allow the background to be painted 

    }

 

    Random r=new Random();

 

    protected override void OnPaint(PaintEventArgs e)

    {

            int h=this.Height/2;

      int w=this.Width/2;

 

      Pen p=new Pen(Color.Black,2);

      int x,y;

      for(x=0,y=0; x<w; x+=w/10, y+=h/10)

      {

        e.Graphics.DrawEllipse(p,x+r.Next(10)-5,y+r.Next(10)-5,this.Width-(2*x),this.Height-(2*y));

      }

 

      p.Dispose();

    }

 

 

  }

}

 

Figure 2 shows the transcontroldemo application in action.

 

Figure 2: A truly transparent control.

 

Caveat Derivor.

The Panel control used in this example is an ideal candidate for transparency retro-fitting because it adds almost nothing to the functionality of ScrollableControl from which it's derived. Panel does little or no painting itself and does not use the double buffered style internally. Other controls which already make assumptions about the way they will display might not be suitable for this technique. For example, any control that uses double buffering internally will certainly not be suitable and will show up with a black, opaque background.

This technique will work well on Control, ScrollableControl Panel and GroupBox and is recommended for those of you that want to create a control more-or-less from scratch.

 

Back to Bob Powell's Windows Forms Tips and Tricks

 

Copyright Robert W. Powell 2003. All rights reserved.