Search code examples
c#winformspaneltransparencyopacity

C# Windows Forms semi-opacity


I have already read many topics about opacity/transparency on Windows Forms in C#, but it's not the effect I would like to get. I would like Form to be 100% transparent, but transparency of the Panel was adjustable, and the transparency effect was transferred to the elements behind Form (Windows desktop, web browser e.t.c.). The attached photo shows the effect that I would like to get (I made them in a graphic program). I will be grateful for your help.

Here is a photo showing the effect I want to get


Solution

  • OP: If there is any other language / environment in which I can deal with this problem, of course I am ready to try it.

    So in addition to Windows Forms solutions, I'll share a WPF solution as well (which is a better framework to satisfy this requirement):

    • Windows Forms - Owned Forms
    • Windows Forms - Layered Windows
    • WPF - Transparent Form and Control Opacity

    Windows Forms - Owned Forms

    As an option you can use Owned Forms.

    Each of the panels can be a top-level border-less Form owned by the main form. The main has a transparency key equal to its back color and those owned forms has opacity. This way you should handle moving of the main form and move the owned forms as well:

    enter image description here

    public partial class MyOwnerForm : Form
    {
        public MyOwnerForm()
        {
            InitializeComponent();
            this.BackColor = Color.Magenta;
            this.TransparencyKey = Color.Magenta;
            this.StartPosition = FormStartPosition.Manual;
            this.DesktopLocation = new Point(100, 100);
            this.ClientSize = new Size(330, 330);
        }
        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            CreateForm(1, new Point(10, 10), new Size(150, 150)).Show();
            CreateForm(0.75, new Point(170, 10), new Size(150, 150)).Show();
            CreateForm(0.50, new Point(10, 170), new Size(150, 150)).Show();
            CreateForm(0.25, new Point(170, 170), new Size(150, 150)).Show();
        }
        protected override void OnMove(EventArgs e)
        {
            base.OnMove(e);
            if(OwnedForms.Length>0)
            {
                var p = PointToScreen(new Point(10, 10));
                var dx = p.X - OwnedForms[0].Location.X;
                var dy = p.Y - OwnedForms[0].Location.Y;
                foreach (var f in OwnedForms)
                    f.Location= new Point(f.Location.X+dx, f.Location.Y+dy);
            }
        }
        Form CreateForm(double opacity, Point location, Size size)
        {
            var f = new Form();
            f.FormBorderStyle = FormBorderStyle.None;
            f.BackColor = Color.Lime;
            f.Opacity = opacity;
            f.StartPosition = FormStartPosition.Manual;
            f.DesktopLocation = PointToScreen(location);
            f.ClientSize = size;
            f.Owner = this;
            f.ShowInTaskbar = false;
            return f;
        }
    }
    

    Windows Forms - Layered Windows

    As an option you can use Layered Windows.

    This way you can create the semi transparent image at run-time and set it as background image of your form. But your form will not receive any paint event and so hosting control on such form is pointless (however they are working and you somehow can force those control repaint).

    enter image description here

    public partial class MyLayeredForm : PerPixelAlphaForm
    {
        public MyLayeredForm()
        {
            InitializeComponent();
            var bm = new Bitmap(230, 230);
            using (var g = Graphics.FromImage(bm))
            {
                using (var b = new SolidBrush(Color.FromArgb(255, Color.Lime)))
                    g.FillRectangle(b, 10, 10, 100, 100);
                using (var b = new SolidBrush(Color.FromArgb(255 * 75 / 100, Color.Lime)))
                    g.FillRectangle(b, 120, 10, 100, 100);
                using (var b = new SolidBrush(Color.FromArgb(255 * 50 / 100, Color.Lime)))
                    g.FillRectangle(b, 10, 120, 100, 100);
                using (var b = new SolidBrush(Color.FromArgb(255 * 25 / 100, Color.Lime)))
                    g.FillRectangle(b, 120, 120, 100, 100);
            }
            this.SelectBitmap(bm);
        }
    }
    

    WPF - Transparent Form and Controls having Opacity

    A better framework to satisfy such UI requirement is WPF.

    To do so, you can set Background of window to Transparent and WindowStyle to None and set AllowTransparency to True. Also for each control you can simply set Opacity value:

    enter image description here

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="261.154" Width="232.923" 
            Background="Transparent" AllowsTransparency="True" 
            WindowStyle="None" WindowStartupLocation="CenterScreen">
        <Grid Margin="0,0,0,0">
            <Grid HorizontalAlignment="Left" Height="100" 
                  Margin="10,10,0,0" VerticalAlignment="Top" 
                  Width="100" Background="Lime" Opacity="1"/>
            <Grid HorizontalAlignment="Left" Height="100"
                  Margin="120,10,0,0" VerticalAlignment="Top"
                  Width="100" Background="Lime" Opacity="0.75" 
                  Grid.ColumnSpan="2"/>
            <Grid HorizontalAlignment="Left" Height="100"
                  Margin="10,120,0,0" VerticalAlignment="Top"
                  Width="100" Background="Lime" Opacity="0.50"/>
            <Grid HorizontalAlignment="Left" Height="100"
                  Margin="120,120,0,0" VerticalAlignment="Top"
                  Width="100" Background="Lime" Opacity="0.25"
                  Grid.ColumnSpan="2"/>
        </Grid>
    </Window>