I'm trying to follow the style guidelines to add a person button to the titlebar but I am unable to make it clickable. (I can tab to it an trigger it via spacebar, but the title bar prevents all interaction)
I followed the recommendations here but none of them work.
The WinAppSdk solution leaves me with the system titlebar overlapping the custom titlebar, and when I click the portion that is showing on the custom titlebar the click does not register.
The UWP solution (Z-Index) does not work either.
ChatGPT says I should implement my own custom drag solution and forget the TitleBar completely. (with a bunch of non-functional code)
Is there a way to make an interactive titlebar in WinUI3? Is there a Git of a working example?
I created a sample app based on the link you provided, and it works.
MainWindow.xaml
<Window
x:Class="TitleBarExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TitleBarExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<Grid
x:Name="AppTitleBar"
Grid.Row="0"
Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition
x:Name="LeftPaddingColumn"
Width="0" />
<ColumnDefinition
x:Name="IconColumn"
Width="Auto" />
<ColumnDefinition
x:Name="TitleColumn"
Width="Auto" />
<ColumnDefinition
x:Name="LeftDragColumn"
Width="*" />
<ColumnDefinition
x:Name="PersonButtonColumn"
Width="Auto" />
<ColumnDefinition
x:Name="RightDragColumn"
Width="*" />
<ColumnDefinition
x:Name="RightPaddingColumn"
Width="0" />
</Grid.ColumnDefinitions>
<Image
x:Name="TitleBarIcon"
Grid.Column="1"
Width="16"
Height="16"
Margin="8,0,0,0"
Source="/Images/WindowIcon.png" />
<TextBlock
x:Name="TitleTextBlock"
Grid.Column="2"
Margin="4,0,0,0"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="App title" />
<Button
x:Name="PersonButton"
Grid.Column="4"
Click="Button_Click"
Content="Person" />
</Grid>
<Grid x:Name="WindowContent">
</Grid>
</Grid>
</Window>
MainWindow.xaml
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using WinRT.Interop;
namespace TitleBarExample;
public sealed partial class MainWindow : Window
{
private readonly AppWindow _appWindow;
public MainWindow()
{
this.InitializeComponent();
_appWindow = GetAppWindowForCurrentWindow();
// Check to see if customization is supported.
// The method returns true on Windows 10 since Windows App SDK 1.2, and on all versions of
// Windows App SDK on Windows 11.
if (AppWindowTitleBar.IsCustomizationSupported() is true)
{
AppWindowTitleBar titleBar = _appWindow.TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ExtendsContentIntoTitleBar = true;
AppTitleBar.Loaded += AppTitleBar_Loaded;
AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
}
else
{
// In the case that title bar customization is not supported, hide the custom title bar
// element.
AppTitleBar.Visibility = Visibility.Collapsed;
// Show alternative UI for any functionality in
// the title bar, such as search.
}
}
internal enum Monitor_DPI_Type : int
{
MDT_Effective_DPI = 0,
MDT_Angular_DPI = 1,
MDT_Raw_DPI = 2,
MDT_Default = MDT_Effective_DPI
}
[DllImport("Shcore.dll", SetLastError = true)]
internal static extern int GetDpiForMonitor(IntPtr hmonitor, Monitor_DPI_Type dpiType, out uint dpiX, out uint dpiY);
private void AppTitleBar_Loaded(object sender, RoutedEventArgs e)
{
// Check to see if customization is supported.
// The method returns true on Windows 10 since Windows App SDK 1.2, and on all versions of
// Windows App SDK on Windows 11.
if (AppWindowTitleBar.IsCustomizationSupported() is true)
{
SetDragRegionForCustomTitleBar(_appWindow);
}
}
private void AppTitleBar_SizeChanged(object sender, SizeChangedEventArgs e)
{
// Check to see if customization is supported.
// The method returns true on Windows 10 since Windows App SDK 1.2, and on all versions of
// Windows App SDK on Windows 11.
if (AppWindowTitleBar.IsCustomizationSupported() is true
&& _appWindow.TitleBar.ExtendsContentIntoTitleBar is true)
{
// Update drag region if the size of the title bar changes.
SetDragRegionForCustomTitleBar(_appWindow);
}
}
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WindowNative.GetWindowHandle(this);
WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(wndId);
}
private double GetScaleAdjustment()
{
IntPtr hWnd = WindowNative.GetWindowHandle(this);
WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
DisplayArea displayArea = DisplayArea.GetFromWindowId(wndId, DisplayAreaFallback.Primary);
IntPtr hMonitor = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId);
// Get DPI.
int result = GetDpiForMonitor(hMonitor, Monitor_DPI_Type.MDT_Default, out uint dpiX, out uint _);
if (result != 0)
{
throw new Exception("Could not get DPI for monitor.");
}
uint scaleFactorPercent = (uint)(((long)dpiX * 100 + (96 >> 1)) / 96);
return scaleFactorPercent / 100.0;
}
private void SetDragRegionForCustomTitleBar(AppWindow appWindow)
{
// Check to see if customization is supported.
// The method returns true on Windows 10 since Windows App SDK 1.2, and on all versions of
// Windows App SDK on Windows 11.
if (AppWindowTitleBar.IsCustomizationSupported() is true
&& appWindow.TitleBar.ExtendsContentIntoTitleBar is true)
{
double scaleAdjustment = GetScaleAdjustment();
RightPaddingColumn.Width = new GridLength(appWindow.TitleBar.RightInset / scaleAdjustment);
LeftPaddingColumn.Width = new GridLength(appWindow.TitleBar.LeftInset / scaleAdjustment);
List<Windows.Graphics.RectInt32> dragRectsList = new();
Windows.Graphics.RectInt32 dragRectL;
dragRectL.X = (int)((LeftPaddingColumn.ActualWidth) * scaleAdjustment);
dragRectL.Y = 0;
dragRectL.Height = (int)(AppTitleBar.ActualHeight * scaleAdjustment);
dragRectL.Width = (int)((IconColumn.ActualWidth
+ TitleColumn.ActualWidth
+ LeftDragColumn.ActualWidth) * scaleAdjustment);
dragRectsList.Add(dragRectL);
Windows.Graphics.RectInt32 dragRectR;
dragRectR.X = (int)((LeftPaddingColumn.ActualWidth
+ IconColumn.ActualWidth
+ TitleTextBlock.ActualWidth
+ LeftDragColumn.ActualWidth
+ PersonButtonColumn.ActualWidth) * scaleAdjustment);
dragRectR.Y = 0;
dragRectR.Height = (int)(AppTitleBar.ActualHeight * scaleAdjustment);
dragRectR.Width = (int)(RightDragColumn.ActualWidth * scaleAdjustment);
dragRectsList.Add(dragRectR);
Windows.Graphics.RectInt32[] dragRects = dragRectsList.ToArray();
appWindow.TitleBar.SetDragRectangles(dragRects);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}