Transparent Windows in WPF

One of the flashiest features of WPF is pervasive transparency. Colors used for borders, backgrounds, text, graphics can all be set to be semi-transparent using the Color Alpha value and in some cases a separate OpacityMask. Transparency can even be used at the window level (in both Vista and XP)! A few warnings before we get into how to do this:

1. This is the kind of stuff that makes Vista require powerful graphics cards, so keep graphics performance in mind.

2. The crazier you make your top level window objects, the crazier you will make your users. This is far beyond changing the template for a button. If you do this incorrectly you can end up with a modal window that can’t be dragged and has no close button. Think about how Joe User would deal with that before you do it.

Now that that’s out of the way, there are a few different properties that affect a Window’s transparency and shape. To affect the Window itself set these properties on the root Window element in XAML (or in code if you prefer). The first property to set is Background. Background is important for setting transparency on just about any WPF element. The key thing to remember when setting the background color is that there are 2 possible settings that will give you a totally see-through object, but will behave differently. The most obvious setting is the Transparent named color (or any #00xxxxxx hex color value). This will give you a window that you can see through but still capture mouse input. The other setting that can be used is the “{x:Null}” markup extension (or null in code) to remove the background entirely. This behaves differently: no background = no mouse input capturing area, but child elements can still capture mouse input as normal. You may want only a partially transparent window, but keep in mind that the window’s area is rectangular so rounded corners or other shapes need to be rendered by child elements so you’re probably better off adding something like a top level Border for your semi-transparent Background on top of the clear Window.

The next important property to set is AllowsTransparency. If this is not set to True your window background will just render as black. If you try running your app now, you’ll get an exception telling you that None is the only valid WindowStyle for a transparent window. This is the last key property in a transparent window: WindowStyle=”None”. Setting this has now removed all of the system’s window controls (Minimize, Maximize, Close) and the system-themed frame. You are now free to make your window look like whatever you want! But you’ve now also lost the standard method of moving and closing a window!

Unless you trust all of your users to be proficient with Alt-F4, it’s probably a good idea to add a close button and maybe a window dragging surface too, just to be nice. The sample app uses a pair of same colored borders to create a thin outer frame and a normal window title bar. Notice however, that the entire window has rounded corners, and the main surface of the app is semi-transparent. There’s also an X button in the top right that’s bound to ApplicationCommands.Close. Here’s what the main window looks like:

normal window

And here’s the XAML:

<Window x:Class="SeeThru.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="SeeThru" Height="300" Width="300"
    WindowStyle="None" AllowsTransparency="True"
    Background="Transparent"
    >
  <Window.Resources>
    <LinearGradientBrush x:Key="WindowFrameBrush" StartPoint="0,0.5" EndPoint="1,0.5">
      <GradientStop Color="CadetBlue" Offset="0.4"/>
      <GradientStop Color="Gray" Offset="1"/>
    </LinearGradientBrush>
  </Window.Resources>
  <Border Background="#50FFFFFF" CornerRadius="5" BorderBrush="{StaticResource WindowFrameBrush}" BorderThickness="2,0,2,2">
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition/>
      </Grid.RowDefinitions>
      <Border Background="{StaticResource WindowFrameBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
              CornerRadius="5,5,0,0" Margin="-1,0,-1,0" MouseLeftButtonDown="DragWindow">
        <Grid>
          <TextBlock Foreground="White" FontWeight="Bold" VerticalAlignment="Center" Margin="10,2,10,2"
            Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=Title}"/>
          <Button Content="X" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5" FontSize="7"
                  Width="15" Height="15" Padding="0" Command="ApplicationCommands.Close"/>
        </Grid>
      </Border>
      <TextBlock Text="This is some text in the window" Grid.Row="1" HorizontalAlignment="Center"
                 VerticalAlignment="Center" TextWrapping="Wrap" FontSize="32"/>
      <Button Content="Click for new window" Click="ButtonClicked" HorizontalAlignment="Center"
              VerticalAlignment="Bottom" Grid.Row="1"/>
    </Grid>
  </Border>
</Window>

We’re not quite done with this window yet. You may have noticed the MouseLeftButtonDown property on the titlebar Border. This needs to be handled in code to allow dragging of the window. The ButtonClicked method is used later for the next window we’ll be creating. We’ll also add the CommandBinding for the Close command that was hooked up to the close button earlier.

        public Window1()
        {
            InitializeComponent();
            CommandBindings.Add(new CommandBinding(ApplicationCommands.Close,
                new ExecutedRoutedEventHandler(delegate(object sender, ExecutedRoutedEventArgs args) { this.Close(); })));
        }
        public void DragWindow(object sender, MouseButtonEventArgs args)
        {
            DragMove();
        }
        public void ButtonClicked(object sender, RoutedEventArgs args)
        {
            CrazyWindow win2 = new CrazyWindow();
            win2.ShowDialog();
        }

We now have a window that looks and behaves almost like a normal window but has a customized look and a semi-transparent main area. But what if you want a different shape for your window? The shape of our first window was provided by a border with rounded corners so it ended up being nearly rectangular. If we forego the top level border any elements that are added will just be rendered in empty space. To make the new window as crazy as possible we’ll use a large spiked path in place of a background. Some text to provide instructions and a text-only title bar are the only other elements in the window. The window background is set to null so the only clickable areas will be inside the visible elements:

<Window x:Class="SeeThru.CrazyWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="A Crazy Window" Height="300" Width="300"
    WindowStyle="None" AllowsTransparency="True"
    Background="{x:Null}"
    >
    <Grid MouseRightButtonDown="WindowClicked">
      <Viewbox Stretch="Uniform">
        <Path Fill="#80D0E0FF" Stroke="Red" StrokeThickness="3" HorizontalAlignment="Center" VerticalAlignment="Center"
              Data="M79,3L65,82 17,91 50,138 96,157 104,192 175,154 190,167 218,78 156,76 157,9 111,39z"/>
      </Viewbox>
      <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=Title}"
                 FontSize="18" Background="Transparent" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20"
                 MouseLeftButtonDown="DragWindow" FontFamily="Impact" Foreground="#C030A060"/>
      <TextBlock Text="Right Click Anywhere to Close" Background="Black" Width="200" Foreground="White"
                 VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="14" TextWrapping="Wrap" />
    </Grid>
</Window>

The code-behind also needs a few handlers for dragging and closing the window.

        public void DragWindow(object sender, MouseButtonEventArgs args)
        {
            DragMove();
        }

        public void WindowClicked(object sender, MouseButtonEventArgs args)
        {
            Close();
        }

crazy window

The new window pops up when the button in the main window is clicked and closes when right clicked. Dragging the floating title moves the window. Here’s the project with both windows:

SeeThru.zip

5 thoughts on “Transparent Windows in WPF

  1. Very Nice brother.
    I was trying this in .net C# for a time.
    Thanks for your code.
    But I am facing an error when I am going to add even handle in the code.

    Help me, because I am very new in WPF.

    Thanks again.

  2. This work pretty well but when I drag my window to the top of my screen (using windows 7) it docks to the the top and I can not drag it anymore.

  3. Dave try this:
    private void Window_StateChanged(object sender, EventArgs e)
    {
    if (this.WindowState == WindowState.Maximized)
    this.WindowState = WindowState.Normal;
    }

    It will take your window back to normal state when it gets maximized. Otherwise make the window state normal before you do the DragMove()

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>