I want to create empty window - transparent and borderless, and make it overlay. To create overlay window, I use AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay)
, to make it borderless i subclass window and using following WndProc:
private unsafe LRESULT SubclassProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
{
if (uMsg == PInvoke.WM_NCCALCSIZE)
{
return new LRESULT(0);
}
return PInvoke.DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
And for make window transparent i use following code:
ICompositionSupportsSystemBackdrop composition = this.As<ICompositionSupportsSystemBackdrop>();
CompositionColorBrush compositionColorBrush = new Compositor().CreateColorBrush(Color.FromArgb(0, 255, 255, 255));
composition.SystemBackdrop = compositionColorBrush;
But i can't hide default close/minimize/maxmimize buttons. I'm using Windows 11.
Full code:
using Microsoft.UI;
using Microsoft.UI.Composition;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Sentry;
using System;
using System.Linq;
using Windows.System;
using Windows.UI;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.System.WinRT;
using Windows.Win32.UI.Shell;
using Windows.Win32.UI.Controls;
using WinRT;
using WinRT.Interop;
using CompositionColorBrush = Windows.UI.Composition.CompositionColorBrush;
using Compositor = Windows.UI.Composition.Compositor;
using System.IO;
using Windows.Win32.UI.WindowsAndMessaging;
using Windows.ApplicationModel.Core;
namespace Widget.UI.Windows
{
internal abstract class OverlayWindow : Window
{
private Grid _rootGrid
{
get
{
if (base.Content is Grid rootGrid)
{
return rootGrid;
}
throw new InvalidOperationException("TopWindow: root isn't initalized");
}
}
public new UIElement? Content
{
get
{
return _rootGrid.Children.FirstOrDefault();
}
set
{
_rootGrid.Children.Clear();
Grid contentGrid = new();
Grid.SetColumn(contentGrid, 0);
Grid.SetRow(contentGrid, 1);
contentGrid.Children.Add(value);
_rootGrid.Children.Add(contentGrid);
}
}
protected HorizontalAlignment HorizontalAlignment
{
set
{
AppWindow.Move(new global::Windows.Graphics.PointInt32()
{
X = value switch
{
HorizontalAlignment.Left => 0,
HorizontalAlignment.Center => (_displayArea.WorkArea.Width - AppWindow.Size.Width) / 2,
HorizontalAlignment.Right => _displayArea.WorkArea.Width - AppWindow.Size.Width,
_ => throw new ArgumentException($"Invalid value (note: HorizontalAlignment.Stretch not supported)")
},
Y = AppWindow.Position.Y
});
}
}
protected VerticalAlignment VerticalAlignment
{
set
{
AppWindow.Move(new global::Windows.Graphics.PointInt32()
{
X = AppWindow.Position.X,
Y = value switch
{
VerticalAlignment.Top => 0,
VerticalAlignment.Center => (_displayArea.WorkArea.Height - AppWindow.Size.Height) / 2,
VerticalAlignment.Bottom => _displayArea.WorkArea.Height - AppWindow.Size.Height,
_ => throw new ArgumentException($"Invalid value (note: VerticalAlignment.Stretch not supported)")
}
});
}
}
private DisplayArea _displayArea
{
get
{
return DisplayArea.GetFromWindowId(Win32Interop.GetWindowIdFromWindow(WindowNative.GetWindowHandle(this)), DisplayAreaFallback.Nearest);
}
}
private SUBCLASSPROC? _subclassProc;
public OverlayWindow()
{
AppWindow.SetPresenter(AppWindowPresenterKind.CompactOverlay);
this.InitializeWindow();
this.InitializeDwmBlur();
this.InitializeComposition();
this.InitializeSubclass();
}
private void InitializeWindow()
{
Grid root = new();
root.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(0) });
root.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
Grid titleBar = new();
Grid.SetColumn(titleBar, 0);
Grid.SetRow(titleBar, 0);
root.Children.Add(titleBar);
root.Loaded += (s, e) =>
{
if (VisualTreeHelper.GetParent(base.Content) is not DependencyObject contentPresenter)
{
return;
}
if (VisualTreeHelper.GetParent(contentPresenter) is not DependencyObject layoutRoot)
{
return;
}
if (VisualTreeHelper.GetChild(layoutRoot, 1) is not Grid titleBar)
{
return;
}
if (VisualTreeHelper.GetChild(titleBar, 0) is not Grid buttonContainer)
{
return;
}
foreach (UIElement child in buttonContainer.Children)
{
child.Visibility = Visibility.Collapsed;
}
// For correct drawing background after creation
PInvoke.SendMessage(_currentHWND, PInvoke.WM_ACTIVATE, new WPARAM(0), new LPARAM(0));
};
this.ExtendsContentIntoTitleBar = true;
this.SetTitleBar(titleBar);
base.Content = root;
}
private void InitializeComposition()
{
EnsureDispatcherQueueExists();
ICompositionSupportsSystemBackdrop composition = this.As<ICompositionSupportsSystemBackdrop>();
CompositionColorBrush compositionColorBrush = new Compositor().CreateColorBrush(Color.FromArgb(0, 255, 255, 255));
composition.SystemBackdrop = compositionColorBrush;
}
private void InitializeDwmBlur()
{
PInvoke.DwmExtendFrameIntoClientArea(_currentHWND, new MARGINS());
PInvoke.DwmEnableBlurBehindWindow(_currentHWND, new DWM_BLURBEHIND()
{
fEnable = true,
dwFlags = PInvoke.DWM_BB_ENABLE | PInvoke.DWM_BB_BLURREGION,
hRgnBlur = PInvoke.CreateRectRgn(-2, -2, 1, -1)
});
}
private void InitializeSubclass()
{
_subclassProc = SubclassProc;
PInvoke.SetWindowSubclass(_currentHWND, _subclassProc, 1000, 0);
}
private unsafe LRESULT SubclassProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
{
if (uMsg == PInvoke.WM_NCCALCSIZE)
{
return new LRESULT(0);
}
return PInvoke.DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
private unsafe void EnsureDispatcherQueueExists()
{
DispatcherQueue dispatcherQueue = global::Windows.System.DispatcherQueue.GetForCurrentThread();
if (dispatcherQueue == null)
{
DispatcherQueueOptions options = new()
{
apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA,
threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT,
dwSize = (uint)sizeof(DispatcherQueueOptions)
};
PInvoke.CreateDispatcherQueueController(options, out DispatcherQueueController _);
}
}
}
}
Hide buttons with
For removing border around window use p/invoke: