How do I make my form transparent, but what I draw on it not? How do I make my form transparent, but what I draw on it not? wpf wpf

How do I make my form transparent, but what I draw on it not?


This is very easily done in WPF:

  1. Set WindowStyle="None" on the Window (note: this is required, you cannot have Transparency and the standard windows chrome)
  2. Set AllowsTransparency="True" on the Window
  3. Set a Background on the Window using a brush with transparency, such as Background="#AAFFFFFF"

Here's a quick sample:

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300" AllowsTransparency="True" Background="#AAFFFFFF" WindowStyle="None"><Grid>    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="Bold">Hello World!</TextBlock></Grid>

Now obviously, since you've disabled the standard Windows chrome, you will need to supply your own button to close/minimize/maximize/drag the window. You can do this pretty easily yourself or you could look into purchasing something like Blendables which comes with a "Chromeless Window" control that you could use.


One workaround that comes to mind is to use two windows overlaid on top of one another. Render the "bottom" window at 50% opacity and then owner draw your text to a window overlaid on top of the other one. If you're doing lable-type displays this might be simple but might get complicated quickly if you need a lot of user input which might then need to get filtered down through to your "main" or "bottom" window.

So, i got it to work, but it's a little squirrelly. The two window solution seemed promissing until i discovered that .Net or Win32 does some weird auto parenting thing when you even implicitly refer to it. Probably has to do with the way the messages are pumped though. The main parent holds the application message pump and int guess is implicitly the parent...

i tried a bunch of workarounds but this timer thing below worked the best. In any case, it might be a clue as to doing it better...


// the "main" or transparent window. Notice it just sets and runs the timerusing System;using System.Windows.Forms;namespace TransparencyPlusNottransparentTest{    public partial class FormMain : Form    {        public FormMain()        {            InitializeComponent();        }

    private void timer1_Tick(object sender, EventArgs e)    {        Program.ShowNontransparency();    }}

}

// the "top" or not transparent window. Notice it does owner draw on// transparent background. The design-time settings are also sans border etc.using System.Drawing;using System.Windows.Forms;

namespace TransparencyPlusNottransparentTest{ public partial class FormTop : Form { public FormTop() { InitializeComponent(); BackColor = Color.Firebrick; TransparencyKey = Color.Firebrick; }

    private void FormTop_Paint(object sender, PaintEventArgs e)    {        e.Graphics.DrawString("Hello Whirrled!", new Font("Tahoma", 14f), Brushes.Black, 10f, 10f );    }}

}

// The control of this whole spiel. It instantiates both windows,// sets the main as the main app window and hosts the public// hacky method to force the non-transparent window to show up on top// and offset so it doesn't obscure the top of the main window.using System;using System.Drawing;using System.Windows.Forms;

namespace TransparencyPlusNottransparentTest{ static class Program { private static FormMain _formMain; private static FormTop _formTop; private const int XY_OFFSET = 30;

    [STAThread]    static void Main()    {        Application.EnableVisualStyles();        Application.SetCompatibleTextRenderingDefault(false);        _formTop = new FormTop();        _formTop.Show(null);        _formMain = new FormMain();        Application.Run(_formMain);    }    public static void ShowNontransparency()    {        _formTop.Location =             new Point(            _formMain.Location.X + XY_OFFSET,             _formMain.Location.Y + XY_OFFSET);        _formTop.BringToFront();    }}

}