PictureBox

PictureBoxを透過させ、背面のコントロールを表示させる方法

Imageプロパティに設定した画像に透過色が設定されている場合、BackColorをColor.TransparentとすればPictureBoxの背景を透過させることはできます。しかしそこに何らかのコントロールが表示されていると、それはPictureBoxの親コントロールの背景色で塗りつぶされてしまいます。この問題はそのコントロールの外観をPictureBoxの背景として描画することで、コントロールが見えているようにすることで解決できます。

protected override void OnPaintBackground(PaintEventArgs e)
{
    base.OnPaintBackground(e);

    using (Bitmap bitmap = new Bitmap(this.Parent.Width, this.Parent.Height))
    {
        ControlCollection parentControls = this.Parent.Controls;
        int ownIndex = parentControls.GetChildIndex(this);

        // このコントロールの背面にあるコントロールを取得する
        IEnumerable<Control> controls = parentControls.Cast<Control>()
            .Where(control => ownIndex < parentControls.GetChildIndex(control) // このコントロールより背面に配置されている
                && control.Bounds.IntersectsWith(this.Bounds)) // このコントロールの領域と交差する
            .OrderByDescending(control => parentControls.GetChildIndex(control)); // コントロールのインデックスの降順に並べ替えることで、重なる順を維持する

        // 背面にあるコントロールの画像を、Bitmapへ描画する
        foreach (Control control in controls)
        {
            control.DrawToBitmap(bitmap, control.Bounds);
        }

        // コントロールの背景として描画する
        e.Graphics.DrawImage(bitmap, -this.Left, -this.Top);
    }
}
c# - Show Transparent Loading Spinner above other Controls - Stack Overflow

背面のコントロールをクリックできるようにする方法

前述の方法ではコントロールが見えているように表示しているだけのため、そのコントロールをクリックしても実際にはPictureBoxがクリックされます。この問題はPictureBoxにWM_NCHITTESTメッセージが送られたときに、HTTRANSPARENTを返すことで解決できます。

protected override void WndProc(ref Message m)
{
    const int WM_NCHITTEST = 0x0084;
    const int HTTRANSPARENT = -1;

    if (m.Msg == WM_NCHITTEST)
    {
        m.Result = new IntPtr(HTTRANSPARENT);
    }
    else
    {
        base.WndProc(ref m);
    }
}
Click through transparency for Visual C# Window Forms? - Stack Overflow WM_NCHITTEST message (Winuser.h) - Win32 apps | Microsoft Learn
Microsoft Learnから検索