Try out this transparent Label Custom Control.
It's similar to the Panel Control you were trying to build, but it's slight different than a Panel (ScrollableControl
): a Panel generates a form of persistence
when its background is drawn (doesn't matter whether you have set ControlStyles.Opaque = false
, so it has no initial background) that causes the background (Color with Alpha or not) to draw over the previous layer.
The Label Control doesn't have this problem.
Drag it on a Container (Form or other child Containers) then stretch it over any other Control: all the controls it overlays will be drawn under it and the translucency
is preserved.
- You can overlay Controls inside other containers (GroupBox included) in a Form or inside child containers.
- You cannot overlay a running ProgressBar (without tweaking the custom Control quite a bit).
See this similar implementation:
Translucent circular Control with text
Also the notes about the use of transparent Panels here:
Transparent Overlapping Circular Progress Bars (Custom Control)
This same effect cannot be achieved using a transparent Label or PictureBox (which you could also use to replace the Label in the code presented here).
The overlay Form Hans Passant linked in comments:
Draw semi transparent overlay image all over the windows form having some controls
works pretty well of course; this is an alternative way, probably easier to use at Design-Time, but clearly not useful in all situations (e.g., when you have to completely overlay a Form).
Note that I've change the range of Opacity
property value from 0-100
to 0-255
: I prefer it this way. Of course you can use whatever numeric range you prefer.
▶ You can overlay scrollable Controls, as a TextBox/RichTextBox, but you cannot let it scroll in any way, it will ruin the party (if you forget to/cannot also invalidate the translucent overlay quick enough).
▶ Also important: the lowest .Net version I test code against is .Net Framework 4.8
(which has changed/updated a lot of things in many departments)
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[DesignerCategory("code")]
public class LabelTransparent : Label, IMessageFilter
{
private const int WS_EX_TRANSPARENT = 0x0020;
private const int WM_PAINT = 0x000F;
private IntPtr m_TopLevelWindow = IntPtr.Zero;
private int m_Opacity = 127;
public LabelTransparent()
{
SetStyle(ControlStyles.Opaque | ControlStyles.Selectable |
ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
public bool PreFilterMessage(ref Message m)
{
if (IsHandleCreated && m_TopLevelWindow != IntPtr.Zero && m.Msg == WM_PAINT) {
var handle = m.HWnd;
if (GetAncestor(handle, 3) != m_TopLevelWindow) return false;
if (handle != this.Handle && handle != Parent?.Handle) {
GetWindowRect(handle, out RECT rect);
if (RectangleToScreen(ClientRectangle).IntersectsWith(rect.ToRectangle())) {
InvalidateOverlapped();
return true;
}
}
}
return false;
}
protected override void OnHandleCreated(EventArgs e)
{
if (!DesignMode) Application.AddMessageFilter(this);
m_TopLevelWindow = FindForm().Handle;
base.OnHandleCreated(e);
}
protected override void OnHandleDestroyed(EventArgs e)
{
if (!DesignMode) Application.RemoveMessageFilter(this);
m_TopLevelWindow = IntPtr.Zero;
base.OnHandleDestroyed(e);
}
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
AutoSize = false;
base.Text = string.Empty;
}
public new Color BackColor {
get => base.BackColor;
set {
if (base.BackColor == value) return;
base.BackColor = value;
InvalidateOverlapped();
}
}
[DefaultValue(127)]
public int Opacity {
get => m_Opacity;
set {
if (m_Opacity == value) return;
m_Opacity = Math.Max(Math.Min(value, 255), 0);
InvalidateOverlapped();
}
}
protected override void OnPaint(PaintEventArgs e)
{
using (var brush = new SolidBrush(Color.FromArgb(m_Opacity, BackColor))) {
e.Graphics.FillRectangle(brush, ClientRectangle);
}
}
private void InvalidateOverlapped() {
if (Parent == null || Parent.Handle == IntPtr.Zero) return;
Parent.Invalidate(Bounds, true);
Parent.Update();
}
[DllImport("user32.dll")]
private static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
[DllImport("User32.dll", SetLastError = true)]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int x, int y, int width, int height) {
Left = x;
Top = y;
Right = x + width;
Bottom = y + height;
}
public Rectangle ToRectangle() => Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}