Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blur behind transparent WPF window

Tags:

c#

wpf

winapi

I am trying to create a WPF application with a semi transparent border-less window that blurs the background behind it.

Here is an example of what I want to do. Screenshot

I have tried to use DwmEnableBlurBehindWindow which works only on windows Vista/7.

I am trying to find a solution that will work on Windows 7, 8 and 10.

like image 992
Tom Avatar asked Aug 03 '15 00:08

Tom


3 Answers

For anyone interested I have found a solution for Windows 10, It looks as though it isn't possible on Windows 8, like David Heffernan mentioned, DwmEnableBlurBehindWindow was removed from Windows 8, however Microsoft re-introduced a solution for achieving this effect in Windows 10.

like image 158
Tom Avatar answered Nov 19 '22 17:11

Tom


I hope I am not late to the party. You can use the SetWindowCompositionAttribute, but you are then forced to set the WindowStyle to "None" and implement your own native Window funtionality and handles. Also inheriting from a custom control is quite complicated. However, long story short. There's BlurryControls.

You can find it via NuGet by browsing for "BlurryControls" or check out the code yourself on GitHub. Eitherway, I hope this is helpful.

On GitHub you will also find a sample application.

like image 4
ConfusedHorse Avatar answered Nov 19 '22 17:11

ConfusedHorse


Windows 8

As much as a dead end that'd better be completely forgotten, we might need to make sure our programs behave consistently across versions. If there is no need for a dynamic background and especially if the window is relatively small (a prime candidate would be a message box or similar over our own application window), the solution of capturing the screen behind the window and blurring it manually might work. In the Loaded event handler:

var screen = window.Owner.PointToScreen(new System.Windows.Point((window.Owner.ActualWidth - window.ActualWidth) / 2, (window.Owner.ActualHeight - window.ActualHeight) / 2));
var rect = new Rectangle((int)screen.X, (int)screen.Y, (int)window.ActualWidth, (int)window.ActualHeight);
var bitmap = new Bitmap(rect.Width, rect.Height);
using (var graphics = Graphics.FromImage(bitmap))
  graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, rect.Size);
border.Background = new ImageBrush(ApplyGaussianBlur(bitmap.ToBitmapImage())) {
  TileMode = TileMode.None,
  Stretch = Stretch.None,
  AlignmentX = AlignmentX.Center,
  AlignmentY = AlignmentY.Center,
};

where border is an outermost Border, normally left completely empty, only used on Windows 8.

The helper function is the usual bitmap conversion:

public static BitmapSource ToBitmapImage(this System.Drawing.Bitmap image) {
  var hBitmap = image.GetHbitmap();
  var bitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
  DeleteObject(hBitmap);
  return bitmap;
}

ApplyGaussianBlur() is best solved with a direct bitmap manipulation package like WriteableBitmapEx, with the necessary modifications.

like image 2
Gábor Avatar answered Nov 19 '22 17:11

Gábor