I am trying to style the entire app title bar on Windows to set the background color purple, but my changes to titleBar.BackgroundColor
and titleBar.InactiveBackgroundColor
are having no effect.
This is how it looks (black parts hidden from the screenshots):
(Click to enlarge)
In ./Platforms/Windows/App.xaml
if I set Background="{StaticResource IIT_Purple}"
on the <Grid>
in the <DataTemplate x:Key="MauiAppTitleBarContainerTemplate">
then it mostly works, but the hamburger menu icon remains without a background color:
(Click to enlarge)
With the <Flyout>
open, the hamburger icon has the correct background color:
(Click to enlarge)
How can I either change the background color of the hamburger icon, or otherwise set the background color of the entire app title bar (without having to set a background color on the <Grid>
?
I am using .NET 8 (definitely) with WinUI 3 (I think).
This should hopefully be all of the relevant code:
./Platforms/Windows/App.xaml
<maui:MauiWinUIApplication
x:Class="YourNamespaceGoesHere.WinUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:YourNamespaceGoesHere.WinUI">
<maui:MauiWinUIApplication.Resources>
<ResourceDictionary>
<!-- TODO: Load these from ./Resources/Styles/Colors.xaml -->
<Color x:Key="IIT_Purple">#6A00FF</Color>
<Color x:Key="IIT_SlightlyLighterPurple">#8200FF</Color>
<!-- Window's chrome / app title bar -->
<DataTemplate x:Key="MauiAppTitleBarContainerTemplate">
<Grid HorizontalAlignment="Stretch" Background="{StaticResource IIT_Purple}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<!-- TODO: Magic number :( -->
<RowDefinition Height="32" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" VerticalAlignment="Center" Foreground="White">
Some App Title Goes Here
</TextBlock>
<ContentControl Grid.Column="1" IsTabStop="False" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" x:Name="AppTitleBarContentControl" />
</Grid>
</DataTemplate>
<!-- Fills up the right gap on the selected flyout item -->
<StaticResource x:Key="NavigationViewItemBackgroundSelected" ResourceKey="SystemControlHighlightListMediumBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundSelectedPointerOver" ResourceKey="SystemControlHighlightListMediumBrush" />
<SolidColorBrush x:Key="SystemControlHighlightListMediumBrush" Color="{StaticResource IIT_SlightlyLighterPurple}" />
<!-- Hides the selected indicator by styling it the same color like a chameleon -->
<StaticResource x:Key="NavigationViewSelectionIndicatorForeground" ResourceKey="SystemControlForegroundAccentBrush" />
<SolidColorBrush x:Key="SystemControlForegroundAccentBrush" Color="{StaticResource IIT_SlightlyLighterPurple}" />
</ResourceDictionary>
</maui:MauiWinUIApplication.Resources>
</maui:MauiWinUIApplication>
I tried changing MauiAppTitleBarContainerTemplate
to MauiAppTitleBarTemplate
but there was no difference.
./Platforms/Windows/App.xaml.cs
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using WinRT.Interop;
using Colors = Microsoft.Maui.Graphics.Colors;
using Controls = Microsoft.Maui.Controls;
namespace YourNamespaceGoesHere.WinUI
{
public partial class App : MauiWinUIApplication
{
public App()
{
this.InitializeComponent();
WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
{
var nativeWindow = handler.PlatformView;
nativeWindow.Activate();
var hWnd = WindowNative.GetWindowHandle(nativeWindow);
var windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
var appWindow = AppWindow.GetFromWindowId(windowId);
var titleBar = appWindow.TitleBar;
// From ./Styles/Colors.xaml
var Resources = Controls.Application.Current!.Resources;
var Color_IIT_PalePurple = Resources.GetResource<Color>("IIT_PalePurple")!.ToWindowsColor();
var Color_IIT_LighterPurple = Resources.GetResource<Color>("IIT_LighterPurple")!.ToWindowsColor();
var Color_IIT_SlightlyLighterPurple = Resources.GetResource<Color>("IIT_SlightlyLighterPurple")!.ToWindowsColor();
var Color_IIT_Purple = Resources.GetResource<Color>("IIT_Purple")!.ToWindowsColor();
var Color_IIT_SlightlyDarkerPurple = Resources.GetResource<Color>("IIT_SlightlyDarkerPurple")!.ToWindowsColor();
var Color_White = Colors.White.ToWindowsColor();
// This first block appears to have no effect
titleBar.ForegroundColor = Color_White;
titleBar.InactiveForegroundColor = Color_White;
titleBar.BackgroundColor = Color_IIT_Purple;
titleBar.InactiveBackgroundColor = Color_IIT_Purple;
// Minimize, Maximize & Close buttons
titleBar.ButtonForegroundColor = Color_White;
titleBar.ButtonInactiveForegroundColor = Color_White;
titleBar.ButtonBackgroundColor = Color_IIT_Purple;
titleBar.ButtonInactiveBackgroundColor = Color_IIT_Purple;
titleBar.ButtonHoverForegroundColor = Color_White;
titleBar.ButtonPressedForegroundColor = Color_White;
titleBar.ButtonHoverBackgroundColor = Color_IIT_SlightlyLighterPurple;
titleBar.ButtonPressedBackgroundColor = Color_IIT_SlightlyDarkerPurple;
});
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}
./Extensions.cs
namespace YourNamespaceGoesHere
{
public static class Extensions
{
public static T? GetResource<T>(this ResourceDictionary dictionary, string key)
{
if(dictionary.TryGetValue(key, out var value) && value is T resource) {
return resource;
} else {
return default;
}
}
}
}
./AppShell.xaml
I've removed the parts that shouldn't be relevant for a minimal required example, like the header and footer:
<?xml version="1.0" encoding="UTF-8" ?>
<Shell
x:Class="YourNamespaceGoesHere.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:YourNamespaceGoesHere"
FlyoutBackgroundColor="{StaticResource IIT_Purple}">
<Shell.ItemTemplate>
<DataTemplate>
<FlexLayout Direction="Row" Style="{StaticResource FlyoutItemStyle}" Margin="10">
<Image Source="{Binding FlyoutIcon}" Margin="0" />
<Label FlexLayout.Grow="1" Text="{Binding Title}" Margin="10,0,0,0" TextColor="{StaticResource White}" FontSize="Body" VerticalTextAlignment="Center" x:Name="_label" HorizontalOptions="StartAndExpand" />
</FlexLayout>
</DataTemplate>
</Shell.ItemTemplate>
<FlyoutItem Title="Home" FlyoutIcon="icon_home.png">
<ShellContent Title="Get Started" Icon="icon_home.png" ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
<FlyoutItem Title="Some Menu Item" FlyoutIcon="icon_some_menu_item.png">
<ShellContent Title="Start" Icon="icon_some_menu_item.png" ContentTemplate="{DataTemplate local:SomeMenuItemPage}" />
</FlyoutItem>
<FlyoutItem Title="Settings" FlyoutIcon="icon_settings.png">
<ShellContent Title="Settings" Icon="icon_setings.png" ContentTemplate="{DataTemplate local:SettingsPage}" />
</FlyoutItem>
</Shell>
./Resources/Styles/Styles.xaml
Just the relevant part that I've changed, with the standard defaults below this:
<!-- Custom styles start -->
<Style TargetType="FlyoutItem">
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource IIT_Purple}, Dark={StaticResource White}}" />
</Style>
<Style Class="FlyoutItemLabelStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource White}"></Setter>
</Style>
<Style x:Key="FlyoutItemStyle" TargetType="FlexLayout">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{StaticResource IIT_SlightlyLighterPurple}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!-- Custom styles end -->
<!-- Customised defaults start -->
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<!-- Hamburger menu icon - white on Windows -->
<Setter Property="Shell.ForegroundColor" Value="{OnPlatform {StaticResource IIT_Purple}, WinUI={StaticResource White}}" />
<Setter Property="Shell.BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource IIT_Purple}}" />
<Setter Property="Shell.FlyoutBackground" Value="{StaticResource IIT_Purple}" />
<Setter Property="Shell.TitleColor" Value="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource SecondaryDarkText}}" />
<Setter Property="Shell.DisabledColor" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="Shell.UnselectedColor" Value="{StaticResource Gray200}" />
<Setter Property="Shell.NavBarHasShadow" Value="False" />
<Setter Property="Shell.TabBarTitleColor" Value="{AppThemeBinding Light={StaticResource IIT_Purple}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}" />
<Setter Property="Shell.TabBarForegroundColor" Value="{AppThemeBinding Light={StaticResource IIT_Purple}, Dark={StaticResource White}}" />
<Setter Property="Shell.TabBarUnselectedColor" Value="{AppThemeBinding Light={StaticResource IIT_LighterPurple}, Dark={StaticResource Gray200}}" />
</Style>
<!-- Customised defaults end -->
I have tried changing these from Gray200
to another color but it did not help:
Shell.DisabledColor
Shell.UnselectedColor
./Resources/Styles/Colors.xaml
Again, just the custom parts, with the defaults below this:
<Color x:Key="IIT_PalePurple">#F7F2FF</Color>
<Color x:Key="IIT_LighterPurple">#AD56FD</Color>
<Color x:Key="IIT_SlightlyLighterPurple">#8200FF</Color>
<Color x:Key="IIT_Purple">#6A00FF</Color>
<Color x:Key="IIT_SlightlyDarkerPurple">#5500CC</Color>
Please let me know if there is anything else that's needed, I'm just conscious that the code required for a minimal example is already quite large.
I would really appreciate any help please!
As an aside, any help loading the colors properly would be amazing too please - I've struggled to get these to work on the WinUI side. I have posted a separate question for that here:
I know there's a bug with the margin of menu items too - until the flyout is opened for a 2nd time (I'll post a question for that one soon).
In ./Platforms/Windows/App.xaml
add:
<Style TargetType="ContentControl" x:Key="WindowChromeStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid x:Name="LayoutRoot" Background="{StaticResource IIT_Purple}">
<ContentPresenter x:Name="ClientAreaPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Foreground="{TemplateBinding Foreground}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Where IIT_Purple
is defined at the top of the same file (like in the original question).
You can then remove Background="{StaticResource IIT_Purple}"
from the <Grid>
(in the code in the same file from the original question).
All of the other code in the original question should be kept.
This successfully changes the entire window's top bar to purple:
(Click to enlarge)
Details on where I found this code are in a comment I left on Alexandar's answer.
All that's left to figure out is how to change the background color of the hamburger icon on hover (it's currently a darker shade of purple, when it should be lighter like the minimize/maximize buttons).