Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a semi transparent form in WPF

Tags:

wpf

I have to develop a semi-transparent form in WPF, but controls should not be transparent.

I have tried different things like setting opacity=0.5 but no result.

  • I know that AllowTransparency can be set to True only if WindowStyle set to None, but I need to show Border as well

UPDATE: Pavlo Glazkov, What is your opinion for this solution

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Opacity="1" AllowsTransparency="True" WindowStyle="None" Background="Transparent">
<Grid Background="Transparent">
    <Border Margin="2,2,12,34" Name="border1" BorderBrush="Lavender" BorderThickness="5" CornerRadius="20,0,20,0"></Border>
    <Button Height="23" Margin="93,101,110,0" Name="button1" VerticalAlignment="Top" Background="CadetBlue" Foreground="White">Hello WPF</Button>
    <Button Height="24" Margin="0,8,20,0" Name="button2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="21" Click="button2_Click">X</Button>
</Grid>
</Window>
like image 318
Student Avatar asked Feb 07 '11 14:02

Student


2 Answers

First, you need to set AllowTransperency to True. Then, you can set the background of the window to a transparent (to desired extent) brush:

<Window x:Class="MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        AllowsTransparency="True"
        Background="{DynamicResource WindowBackground}">
    <Window.Resources>
       <SolidColorBrush x:Key="WindowBackground" 
                        Color="White"
                        Opacity="0.5"/>
    </Window.Resources>
    ...
</Window>

Please note that AllowTransperency can be set to True only if WindowStyle set to None.

Update: If you don't want to set WindowStyle to None and would like to keep standart border and window buttons there is an alternative that will work only on Windows Vista/7 with Windows Aero theme.

The trick is that you can extend the "Glass" area to the whole window using the following code:

public static class WindowUtils
{
    /// <summary>
    /// Extends the glass area into the client area of the window
    /// </summary>
    /// <param name="window">Window to extend the glass on.</param>
    /// <param name="thikness">Thickness of border to extend.</param>
    public static void ExtendGlass(this Window window, Thickness thikness) {
        try {
            int isGlassEnabled = 0;
            Win32.DwmIsCompositionEnabled(ref isGlassEnabled);
            if (Environment.OSVersion.Version.Major > 5 && isGlassEnabled > 0) {
                // Get the window handle
                var helper = new WindowInteropHelper(window);
                var mainWindowSrc = HwndSource.FromHwnd(helper.Handle);

                if (mainWindowSrc != null) {
                    if (mainWindowSrc.CompositionTarget != null) {
                        mainWindowSrc.CompositionTarget.BackgroundColor = Colors.Transparent;
                    }

                    // Get the dpi of the screen
                    System.Drawing.Graphics desktop =
                        System.Drawing.Graphics.FromHwnd(mainWindowSrc.Handle);

                    float dpiX = desktop.DpiX / 96;
                    float dpiY = desktop.DpiY / 96;

                    // Set Margins
                    var margins = new MARGINS {
                        cxLeftWidth = (int)(thikness.Left * dpiX),
                        cxRightWidth = (int)(thikness.Right * dpiX),
                        cyBottomHeight = (int)(thikness.Bottom * dpiY),
                        cyTopHeight = (int)(thikness.Top * dpiY)
                    };

                    window.Background = Brushes.Transparent;

                    Win32.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
                }
            }
            else {
                window.Background = SystemColors.WindowBrush;
            }
        }
        catch (DllNotFoundException) {

        }
    }
}

public class Win32
{
    [DllImport("dwmapi.dll")]
    public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);

    [DllImport("dwmapi.dll")]
    public static extern int DwmIsCompositionEnabled(ref int en);

    [DllImport("user32.dll")]
    public static extern bool SetCursorPos(int X, int Y);


    [DllImport("User32", EntryPoint = "ClientToScreen", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern int ClientToScreen(IntPtr hWnd, [In, Out] POINT pt);
}

[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
    public int cxLeftWidth;
    public int cxRightWidth;
    public int cyTopHeight;
    public int cyBottomHeight;
}

[StructLayout(LayoutKind.Sequential)]
public class POINT
{
    public int x = 0;
    public int y = 0;
}

To extend the glass to the whole window you need to call the ExtendGlass extension method in a SizeChanged event handler of the window and pass a Thickness that covers whole window:

public MyWindow() {
    InitializeComponent();

    SizeChanged += OnSizeChanged;
}

private void OnSizeChanged(object sender, SizeChangedEventArgs e) {
    double horisontalThickness = Width / 2;
    double verticalThickness = Height / 2;

    var glassThickness = new Thickness(horisontalThickness, verticalThickness, horisontalThickness, verticalThickness);

    this.ExtendGlass(glassThickness);
}
like image 79
Pavlo Glazkov Avatar answered Oct 24 '22 21:10

Pavlo Glazkov


You could try this, it will create a Glass Background for your Window (looks like the Vista and Windows7 transparency effect)

Here is some further explanation from Microsoft.

like image 41
Tokk Avatar answered Oct 24 '22 19:10

Tokk