1

I'm drawing a panel on a bitmap in picturebox using C#. I used below code, which is fine when I don't minimize the Form. When I minimize the Form and again maximize it to the first size, all panels which were drawn by this class, show black background. I found that when I change ControlStyles.Opaque to something else such as "SupportsTransparentBackColor" the problem would be fixed but the panels would not be transparent anymore.

public class ExtendedPanel : Panel
{
    private const int WS_EX_TRANSPARENT = 0x00;
    public ExtendedPanel()
    {
         SetStyle(ControlStyles.Opaque, true);
    }

private int opacity = 1;
[DefaultValue(1)]
public int Opacity
{
    get
    {
        return this.opacity;
    }
    set
    {
        if (value < 0 || value > 100)
            throw new ArgumentException("value must be between 0 and 100");
        this.opacity = value;
    }
}
protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
        return cp;
    }
}
protected override void OnPaint(PaintEventArgs e)
{
    using (var brush = new SolidBrush(Color.FromArgb(this.opacity * 1 / 100, this.BackColor)))
    {
        e.Graphics.FillRectangle(brush, this.ClientRectangle);
    }
    base.OnPaint(e);
}

}

Elnaz Yousefi
  • 195
  • 1
  • 3
  • 17

1 Answers1

4

Reza Aghaei already told you what was actually preventing the Panel transparency to work at all:
WS_EX_TRANSPARENT was set to 0x00 instead of 0x20.

Some suggestions to improve the appearace of the translucent Panel.

  • Test the Panel setting these Styles:

This will prevent any artifact on the Panel when you're moving it both at Desing-Time and Run-Time.

SetStyle(ControlStyles.AllPaintingInWmPaint |
         ControlStyles.UserPaint |
         ControlStyles.Opaque, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
  • When setting the opacity value:

Use Refresh() if it's Desing-Time, this will update the new Opacity visual immediately. Othrerwise, you'll have to click on the Form to see the changes. At Run-Time, Invalidate() is enough (usually).

set {
    if (value < 0 || value > 255) throw new ArgumentException("value must be between 0 and 255");
    opacity = value;
    if (DesignMode) FindForm().Refresh();
    Invalidate();
}

Modified test class:

public class ExtendedPanel : Panel
{
    private const int WS_EX_TRANSPARENT = 0x20;
    public ExtendedPanel() {
        SetStyle(ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.UserPaint |
                 ControlStyles.Opaque, true);
        SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
        DoubleBuffered = false;
    }

    private int opacity = 1;

    [DefaultValue(1)]
    public int Opacity {
        get => opacity;
        set {
            if (value < 0 || value > 255) throw new ArgumentException("value must be between 0 and 255");
            opacity = value;
            if (DesignMode) FindForm().Refresh();
            Invalidate();
        }
    }

    protected override CreateParams CreateParams {
        get {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
            return cp;
        }
    }

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        using (var brush = new SolidBrush(Color.FromArgb(opacity, BackColor))) {
            e.Graphics.FillRectangle(brush, ClientRectangle);
        }
    }
}
Jimi
  • 29,621
  • 8
  • 43
  • 61