how to Customize Titlebar in winui 3? #3951
-
The following methods are created in order:
With version 1.4, new API were introduced for the title bar. My question is, should we use the first method + InputNonClientPointerSource or the second method + InputNonClientPointerSource to use these new API? I've seen the gallery codes and I'm a bit confused:
but then in sample codes we can see Window.SetTitlebar is used!
Therefore, which one should we use to use the latest changes and the best method for customizing? Definitely, to calculate the drag areas, from the last method, but which one for customizing the titlebar? @pratikone Since you made the latest changes to the gallery, can you help? |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 4 replies
-
It shouldn't matter, since as the release notes state Microsoft.UI.Xaml.Window.ExtendsContentIntoTitleBar uses the same implementation as Microsoft.UI.Windowing.AppWindowTitleBar.ExtendsContentIntoTitleBar. However, there is an issue where:
So it is currently better to use Microsoft.UI.Xaml.Window.ExtendsContentIntoTitleBar. |
Beta Was this translation helpful? Give feedback.
-
In fact, winui 3 doesn't provide a convenient way to customize the title bar. So, I created a way to customize the title bar prior to WASDK 1.4 and it was simple and easy to use: using System;
using System.Collections.Generic;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace App1.Controls;
public static class WinUITitleBar
{
public static readonly DependencyProperty IsWindowTitleBarProperty =
DependencyProperty.RegisterAttached("IsWindowTitleBar", typeof(bool),
typeof(WinUITitleBar), new PropertyMetadata(false, OnIsWindowTitleBarChangedCallback));
public static bool GetIsWindowTitleBar(Grid obj)
{
return (bool)obj.GetValue(IsWindowTitleBarProperty);
}
public static void SetIsWindowTitleBar(Grid obj, bool value)
{
obj.SetValue(IsWindowTitleBarProperty, value);
}
private static void OnIsWindowTitleBarChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Grid titleBar)
{
void OnTitleBarLayoutUpdated(object? sender, object e)
{
// sender is null in here!?
UpdateDragRegionForCustomTitleBar(titleBar);
}
titleBar.LayoutUpdated -= OnTitleBarLayoutUpdated;
if (e.NewValue is bool b && b)
{
titleBar.LayoutUpdated += OnTitleBarLayoutUpdated;
}
}
}
private static void UpdateDragRegionForCustomTitleBar(Grid titleBar)
{
if (titleBar is not { IsLoaded: true, XamlRoot: { } xamlRoot })
{
return;
}
var columnDefinitions = titleBar.ColumnDefinitions;
var columnDefinitionsCount = columnDefinitions.Count;
var scaleAdjustment = xamlRoot.RasterizationScale;
var dragRectsList = new List<Windows.Graphics.RectInt32>();
int x = 0, height = (int)Math.Round(titleBar.ActualHeight * scaleAdjustment);
for (var i = 0; i < columnDefinitionsCount; i++)
{
var column = columnDefinitions[i];
var physicalWidth = (int)Math.Round(column.ActualWidth * scaleAdjustment);
if (GetUIContentType(column) is WinUITitleBarUIContentType.Caption)
{
dragRectsList.Add(new() { X = x, Height = height, Width = physicalWidth });
}
x += physicalWidth;
}
var appWindowId = xamlRoot.ContentIslandEnvironment.AppWindowId;
AppWindow.GetFromWindowId(appWindowId).TitleBar.SetDragRectangles([.. dragRectsList]);
}
public static readonly DependencyProperty UIContentTypeProperty =
DependencyProperty.RegisterAttached("UIContentType", typeof(WinUITitleBarUIContentType),
typeof(WinUITitleBar), new PropertyMetadata(WinUITitleBarUIContentType.Caption));
public static WinUITitleBarUIContentType GetUIContentType(ColumnDefinition obj)
{
return (WinUITitleBarUIContentType)obj.GetValue(UIContentTypeProperty);
}
public static void SetUIContentType(ColumnDefinition obj, WinUITitleBarUIContentType value)
{
obj.SetValue(UIContentTypeProperty, value);
}
}
public enum WinUITitleBarUIContentType
{
// HTCATPION
Caption,
// CLIENT AREA
Client
} First, set the ExtendsContentIntoTitleBar to true in the main window. // ....
public MainWindow()
{
InitializeComponent();
ExtendsContentIntoTitleBar = true;
}
// .... And then we can define the custom title bar in xaml: <!-- xmlns:ctrls="using:App1.Controls" -->
<Grid>
<Grid.RowDefinitions>
<!-- Title bar -->
<RowDefinition Height="Auto" />
<!-- Client Area -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Height="32" ctrls:WinUITitleBar.IsWindowTitleBar="True">
<Grid.ColumnDefinitions>
<!-- [0] Left Padding -->
<ColumnDefinition Width="4" ctrls:WinUITitleBar.UIContentType="Caption" />
<!-- [1] Column of BackButton -->
<ColumnDefinition Width="Auto" ctrls:WinUITitleBar.UIContentType="Client" />
<!-- [2] Padding -->
<ColumnDefinition Width=".2*" ctrls:WinUITitleBar.UIContentType="Caption" />
<!-- [3] Column of SearchBox -->
<ColumnDefinition Width="*" ctrls:WinUITitleBar.UIContentType="Client" />
<!-- [4] Padding -->
<ColumnDefinition Width=".4*" ctrls:WinUITitleBar.UIContentType="Caption" />
<!-- [5] Right Padding -->
<ColumnDefinition Width="192" ctrls:WinUITitleBar.UIContentType="Caption" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Width="32"
Height="32"
Padding="8">
<Viewbox Width="12" Height="12">
<SymbolIcon Symbol="Back" />
</Viewbox>
</Button>
<AutoSuggestBox
Grid.Column="3"
PlaceholderText="Search..."
QueryIcon="Find" />
</Grid>
</Grid> We use "Client" to indicate that the column is in the client area, "Caption" is in the title bar. (If that column is "Caption", then elements in that column cannot be interacted with.)
This is a way to customize the title bar based on the grid and columns, and it's done with attached properties, but importantly, it's not complicated and easy to use (I think^^). This copy from my repo, you can get it in WinUITitleBar.cs . |
Beta Was this translation helpful? Give feedback.
-
@Wenveo Why make things difficult when they are so simple? winui 3 now support interactive elements and use AppWindow Titlebar customization so we can define drag regions with new api and calculating drag regions is so much easy.
|
Beta Was this translation helpful? Give feedback.
-
There seems a bug with |
Beta Was this translation helpful? Give feedback.
-
WASDK 1.6 will have https://learn.microsoft.com/windows/apps/windows-app-sdk/experimental-channel#new-titlebar-control 🥳 |
Beta Was this translation helpful? Give feedback.
It shouldn't matter, since as the release notes state Microsoft.UI.Xaml.Window.ExtendsContentIntoTitleBar uses the same implementation as Microsoft.UI.Windowing.AppWindowTitleBar.ExtendsContentIntoTitleBar.
However, there is an issue where:
So it is currently better to use Microsoft.UI.Xaml.Window.ExtendsCo…