WPF glass window with no border and no resize out of focus
Asked Answered
G

1

5

I am trying to create a Aero glass borderless and non-resizable WPF window using the DwmEnableBlurBehindWindow method from the DmwAPI. However, for some strange reason the glass color of this window appears as if the window is out of focus. As you can see in the next three images, the normal windows with borders (e.g figure 1 and 2) work just fine and react as expected (dark blue in focus, whitish when out of focus (= non active)).

DwmEnableBlurBehindWindow with ToolWindow DwmEnableBlurBehindWindow with ToolWindow out of focus

The borderless window with resizing allowed, shows the same behavior:

DwmEnableBlurBehindWindow with borderless but resizable window

The non-resizable borderless window however will always look as if it is out of focus (as you can see in the last figure 3) both when it is active and non-active. It always looks whitish:

DwmEnableBlurBehindWindow with borderless and non-resizable window

This is some example code of how I set the glass style:

public MainWindow()
{
    InitializeComponent();

    WindowStyle = WindowStyle.None;
    ResizeMode = ResizeMode.NoResize;

    Height = 200;

    Background = Brushes.Transparent;
    Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    var windowInteropHelper = new WindowInteropHelper(this);
    var handle = windowInteropHelper.Handle;
    var mainWindowSrc = HwndSource.FromHwnd(handle);

    if (mainWindowSrc != null)
        if (mainWindowSrc.CompositionTarget != null)
            mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
    var glassParams = new DwmApi.DwmBlurbehind
    {
        dwFlags = DwmApi.DwmBlurbehind.DWM_BB_ENABLE,
        fEnable = true,
        hRegionBlur = IntPtr.Zero
    };

    IntPtr dis = new IntPtr(2);
    DwmApi.DwmSetWindowAttribute(mainWindowSrc.Handle,
                DwmApi.DwmWindowAttribute.DWMWA_LAST,
                dis,
                sizeof(uint));

    DwmApi.DwmEnableBlurBehindWindow(
        handle,
        glassParams
        );
}

I tried focusing the window, but that doesn't seem to affect the behavior. Any ideas or pointers on how to solve this?

Gangway answered 22/6, 2013 at 0:37 Comment(0)
P
7

I haven't worked much in dwm apis so I may be wrong but I think the default dwm rendering policy is using WindowStyle to figure out rendering. If you disable that policy, it behaves as you'd expect it to.

Add the following bit to fix your blues xD

const int DWMWA_NCRENDERING_POLICY = 2;
int DWMNCRP_DISABLED = 2;

DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, ref DWMNCRP_DISABLED, sizeof(int));

For details of this voodoo, please check the following resources:

DwmSetWindowAttribute function

DWMWINDOWATTRIBUTE enumeration

MainWindow.xaml

<Window x:Class="dwm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"/>

MainWindow.xaml.cs

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace dwm
{
    public partial class MainWindow
    {
        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DwmBlurbehind blurBehind);

        [DllImport("dwmapi.dll", PreserveSig = true)]
        private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);

        public MainWindow()
        {
            InitializeComponent();
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            var bb = new DwmBlurbehind
            {
                dwFlags = CoreNativeMethods.DwmBlurBehindDwFlags.DwmBbEnable,
                Enabled = true
            };

            WindowStartupLocation = WindowStartupLocation.CenterScreen;
            Background = Brushes.Transparent;
            ResizeMode = ResizeMode.NoResize;
            WindowStyle = WindowStyle.None;

            Focus();

            var hwnd = new WindowInteropHelper(this).Handle;

            HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;

            DwmEnableBlurBehindWindow(hwnd, ref bb);

            const int dwmwaNcrenderingPolicy = 2;
            var dwmncrpDisabled = 2;

            DwmSetWindowAttribute(hwnd, dwmwaNcrenderingPolicy, ref dwmncrpDisabled, sizeof(int));
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct DwmBlurbehind
        {
            public CoreNativeMethods.DwmBlurBehindDwFlags dwFlags;
            public bool Enabled;
            public IntPtr BlurRegion;
            public bool TransitionOnMaximized;
        }

        public static class CoreNativeMethods
        {
            public enum DwmBlurBehindDwFlags
            {
                DwmBbEnable = 1,
                DwmBbBlurRegion = 2,
                DwmBbTransitionOnMaximized = 4
            }
        }
    }
}

Screenshot with focus

Screenshot with focus

Screenshot without focus

Screenoshot without focus

Test Environment

OS: Windows 8 - x64

Theme: Standard windows

Politician answered 24/6, 2013 at 12:44 Comment(6)
I have tried this before and tried it again now, but no luck unfortunately: ` IntPtr dis = new IntPtr(2); DwmApi.DwmSetWindowAttribute(mainWindowSrc.Handle, DwmApi.DwmWindowAttribute.DWMWA_NCRENDERING_POLICY, dis, sizeof(uint));`Gangway
Will need to see more code as I can reproduce your issue exactly as you describe and fix it with the code above. Perhaps we can switch to a room discussion. I'm online pretty much all working days (GMT+1) in WPF roomPolitician
I haven't looked at your code yet, but I think I found your problem. You're using IntPtr and I'm using ref int. Indeed my code fails to work if I use your method signature. Try switching to ref int and see if it works for you.Politician
@StevenHouben I just used your entire code bit changing the method signature to ref int and your code works as well.Politician
Thanks, it works! One more thing: any idea on how to prevent the window from going out of focus? I need it to behave similar to the taskbar.Gangway
No sorry, not off the top of my head right now. Will have to research.Politician

© 2022 - 2024 — McMap. All rights reserved.