☰
UWP 标题栏定制实战:基于 Windows-universal-samples TitleBar 示例的四种自定义方案
2026/9/25 7:04:09 网站建设 项目流程
  • 示例工程

【免费下载链接】Windows-universal-samples

API samples for the Universal Windows Platform.

项目地址:https://gitcode.com/gh_mirrors/wi/Windows-universal-samples
点击查看免费下载

本指南以 Windows-universal-samples 仓库中的 TitleBar 示例(Samples/TitleBar/README.md)为骨架,完整讲解 UWP 应用中标题栏自定义的四种核心技术:定制系统标题栏颜色、将视图扩展到标题栏区域绘制自定义标题栏、响应标题栏状态变化,以及在标题栏中绘制控件。读完本文,你将掌握ApplicationViewTitleBar与CoreApplicationViewTitleBar两套 API 的完整用法,并能直接照搬示例代码到自己的 UWP 项目中。

示例概览:一个示例,四种标题栏定制技巧

TitleBar 示例是一个典型的 UWP 功能演示(sample),属于ControlsLayoutAndText类别,其 frontmatter 声明了它支持 C#、C++/CX 与 C++/WinRT 三种语言版本(仓库中对应cs/、cpp/、cppwinrt/三个子目录)。示例演示了以下四种标题栏定制技术:

  • 定制标准系统标题栏中的颜色:不改变标题栏布局,只通过 API 修改标题栏背景、前景以及最小化/最大化/关闭按钮的配色。
  • 将视图扩展到标题栏区域:开启ExtendViewIntoTitleBar后,应用可以渲染到原本由系统标题栏占据的空间,从而绘制完全自定义的标题栏。
  • 响应标题栏状态变化:订阅LayoutMetricsChanged、IsVisibleChanged等事件,在标题栏尺寸、可见性、全屏模式变化时动态调整应用 UI。
  • 在标题栏中绘制控件(仅 XAML 可用):通过Window.SetTitleBar把自定义元素指定为标题栏的可拖动区域,并在其中放置 CheckBox 等交互控件。

需要注意的是:并非所有标题栏功能在所有 Windows 10 构建版本中都可用,功能会随新版本逐步发布;示例运行环境要求为 Windows 10,并使用 Visual Studio 构建。

从源码结构看,示例由两个可切换的场景页组成,注册于 SampleConfiguration.cs:

List<Scenario> scenarios = new List<Scenario> { new Scenario() { Title="Custom colors", ClassType=typeof(Scenario1_Colors)}, new Scenario() { Title="Custom drawing", ClassType=typeof(Scenario2_Extend)}, };
  • Scenario1(Custom colors):演示标题栏及按钮颜色定制;
  • Scenario2(Custom drawing):演示视图扩展进标题栏、全屏模式切换与自定义标题栏的挂载/移除。

系统要求

按示例 README 的说明,运行本示例需要:

  • Windows 10操作系统;
  • Microsoft Visual Studio(用于构建与部署 UWP 应用)。

标题栏相关 API 属于Windows.UI.ViewManagement与Windows.ApplicationModel.Core命名空间,仅在 UWP 应用模型中可用。

构建示例

示例 README 给出了标准的构建流程,按以下步骤操作即可:

  1. 若下载的是 samples ZIP 压缩包,务必解压整个压缩包,而不仅是包含目标示例的单个文件夹——仓库中的示例共享SharedContent依赖,只解压局部会导致构建失败(压缩包结构同时包含SharedContent与LICENSE,见 README frontmatter 的extendedZipContent声明)。
  2. 启动 Visual Studio,选择File>Open>Project/Solution。
  3. 在解压目录下依次进入 Samples 子文件夹 → 本示例文件夹(TitleBar)→ 选择语言子目录(C# 对应cs/、C++/CX 对应cpp/、C++/WinRT 对应cppwinrt/),双击其中的解决方案文件(.sln)。
  4. 按Ctrl+Shift+B或选择Build>Build Solution完成构建。

运行示例

构建成功后,部署与运行方式取决于你的需求:

  • 仅部署:选择Build>Deploy Solution。
  • 部署并调试运行:按F5或选择Debug>Start Debugging。
  • 部署但不调试运行:按Ctrl+F5或选择Debug>Start Without Debugging。

场景一:自定义标题栏颜色(ApplicationViewTitleBar)

示例的第一种定制方式是"不改布局、只改配色"。核心对象是ApplicationView.GetForCurrentView().TitleBar,类型为ApplicationViewTitleBar。场景页在构造函数中获取该对象并依据当前颜色状态反推单选按钮(见 Scenario1_Colors.xaml.cs):

titleBar = ApplicationView.GetForCurrentView().TitleBar; // Infer the radio button selection from the title bar colors. if (titleBar.ButtonBackgroundColor == null) { UseStandardColors.IsChecked = true; } else if (titleBar.ButtonBackgroundColor.Value.A > 0) { UseCustomColors.IsChecked = true; } else { TransparentWhenExtended.IsChecked = true; }

可定制的 12 个颜色属性

ApplicationViewTitleBar共暴露 12 个可写颜色属性,覆盖标题栏主体与按钮两套状态(活动/非活动、默认/悬停/按下)。示例 UI(Scenario1_Colors.xaml)通过数据绑定实时展示这些属性,完整清单如下:

类别属性说明
标题栏背景BackgroundColor窗口活动时的标题栏背景色
标题栏前景ForegroundColor窗口活动时的标题栏文字/图标前景色
标题栏背景(非活动)InactiveBackgroundColor窗口非活动时的背景色
标题栏前景(非活动)InactiveForegroundColor窗口非活动时的前景色
按钮背景ButtonBackgroundColor最小化/最大化/关闭按钮默认背景色
按钮悬停背景ButtonHoverBackgroundColor按钮悬停时的背景色
按钮按下背景ButtonPressedBackgroundColor按钮按下时的背景色
按钮非活动背景ButtonInactiveBackgroundColor窗口非活动时按钮的背景色
按钮前景ButtonForegroundColor按钮默认前景色
按钮悬停前景ButtonHoverForegroundColor按钮悬停时的前景色
按钮按下前景ButtonPressedForegroundColor按钮按下时的前景色
按钮非活动前景ButtonInactiveForegroundColor窗口非活动时按钮的前景色

恢复系统默认颜色:赋值为 null

示例中"Use standard colors"单选按钮的处理逻辑展示了恢复默认的正确做法——将所有 12 个属性显式置为null(见 Scenario1_Colors.xaml.cs):

// Setting colors to null returns them to system defaults. titleBar.BackgroundColor = null; titleBar.ForegroundColor = null; titleBar.InactiveBackgroundColor = null; titleBar.InactiveForegroundColor = null; titleBar.ButtonBackgroundColor = null; titleBar.ButtonHoverBackgroundColor = null; titleBar.ButtonPressedBackgroundColor = null; titleBar.ButtonInactiveBackgroundColor = null; titleBar.ButtonForegroundColor = null; titleBar.ButtonHoverForegroundColor = null; titleBar.ButtonPressedForegroundColor = null; titleBar.ButtonInactiveForegroundColor = null;

因此,判断某颜色是否被自定义时,应检查对应属性是否为null(这也是示例代码反推单选按钮状态的依据)。

Alpha 通道的语义:关键细节

示例源码中注释与取值逻辑给出了一个容易踩坑的规则(Scenario1_Colors.xaml.cs):

// Title bar colors. Alpha must be 255. titleBar.BackgroundColor = new Color() { A = 255, R = 54, G = 60, B = 116 }; titleBar.ForegroundColor = new Color() { A = 255, R = 232, G = 211, B = 162 }; titleBar.InactiveBackgroundColor = new Color() { A = 255, R = 135, G = 141, B = 199 }; titleBar.InactiveForegroundColor = new Color() { A = 255, R = 232, G = 211, B = 162 }; // Title bar button background colors. Alpha is respected when the view is extended // into the title bar (see scenario 2). Otherwise, Alpha is ignored and treated as if it were 255. byte buttonAlpha = (byte)(TransparentWhenExtended.IsChecked.Value ? 0 : 255); titleBar.ButtonBackgroundColor = new Color() { A = buttonAlpha, R = 54, G = 60, B = 116 }; titleBar.ButtonHoverBackgroundColor = new Color() { A = buttonAlpha, R = 19, G = 21, B = 40 }; titleBar.ButtonPressedBackgroundColor = new Color() { A = buttonAlpha, R = 232, G = 211, B = 162 }; titleBar.ButtonInactiveBackgroundColor = new Color() { A = buttonAlpha, R = 135, G = 141, B = 199 }; // Title bar button foreground colors. Alpha must be 255. titleBar.ButtonForegroundColor = new Color() { A = 255, R = 232, G = 211, B = 162 }; titleBar.ButtonHoverForegroundColor = new Color() { A = 255, R = 255, G = 255, B = 255 }; titleBar.ButtonPressedForegroundColor = new Color() { A = 255, R = 54, G = 60, B = 116 }; titleBar.ButtonInactiveForegroundColor = new Color() { A = 255, R = 232, G = 211, B = 162 };

归纳为三条规则:

  1. 标题栏本体颜色(背景/前景,含活动与非活动)的 Alpha 必须为 255,即不支持半透明标题栏。
  2. 按钮背景色的 Alpha 仅在视图扩展进标题栏时被尊重;未扩展时 Alpha 被忽略、按 255 处理。示例中的"Transparent when extended"模式即利用这一点:将按钮背景 Alpha 设为 0,使按钮在自定义标题栏背景下"隐形",仅在扩展模式下生效。
  3. 按钮前景色的 Alpha 必须为 255。

场景二:将视图扩展到标题栏(CoreApplicationViewTitleBar)

第二种定制方式彻底接管标题栏外观。其核心开关是CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar。场景页的 CheckBox 与它双向同步(见 Scenario2_Extend.xaml.cs):

private void ExtendView_Click(object sender, RoutedEventArgs e) { bool extend = ExtendView.IsChecked.Value; CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = extend; EnableControls.Visibility = extend ? Visibility.Visible : Visibility.Collapsed; if (extend) { rootPage.AddCustomTitleBar(); } else { rootPage.RemoveCustomTitleBar(); } }

开启后,应用即可在原本被系统标题栏占据的空间中自由绘制;同时标题栏按钮背景的 Alpha 通道开始生效(对应场景一中的规则 2)。此时必须借助CoreApplicationViewTitleBar的布局属性,让自定义标题栏与系统标题栏在尺寸和位置上精确对齐。

布局指标:Height 与 SystemOverlay 内边距

CoreApplicationViewTitleBar提供三个关键布局来源,示例通过INotifyPropertyChanged数据绑定把它们喂给 XAML(见 CustomTitleBar.xaml.cs):

public Thickness CoreTitleBarPadding { get { // The SystemOverlayLeftInset and SystemOverlayRightInset values are // in terms of physical left and right. Therefore, we need to flip // then when our flow direction is RTL. if (FlowDirection == FlowDirection.LeftToRight) { return new Thickness() { Left = coreTitleBar.SystemOverlayLeftInset, Right = coreTitleBar.SystemOverlayRightInset }; } else { return new Thickness() { Left = coreTitleBar.SystemOverlayRightInset, Right = coreTitleBar.SystemOverlayLeftInset }; } } } public double CoreTitleBarHeight { get { return coreTitleBar.Height; } }
属性用途
Height系统标题栏的高度,用于给自定义标题栏 Grid 定高
SystemOverlayLeftInset左侧系统 UI 区域宽度(含窗口按钮等系统叠加元素),用于给自定义标题栏内容留出左侧安全边距
SystemOverlayRightInset右侧系统 UI 区域宽度(如最小化/最大化/关闭按钮占位),用于留出右侧安全边距
IsVisible标题栏当前是否可见(全屏模式下可能隐藏)

示例 XAML(CustomTitleBar.xaml)将二者直接绑定到布局:

<Grid x:Name="TitleBar" VerticalAlignment="Top" Height="{x:Bind CoreTitleBarHeight, Mode=OneWay}" Canvas.ZIndex="3"> <Rectangle x:Name="BackgroundElement" Fill="DarkGreen" /> <Grid Padding="{x:Bind CoreTitleBarPadding, Mode=OneWay}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="Custom Title Bar" FontStyle="Italic"/> <CheckBox Grid.Column="1" x:Name="TitleBarControl" Visibility="Collapsed">Checkbox in title bar</CheckBox> </Grid> </Grid>

C++/WinRT 版本的实现在 CustomTitleBar.cpp 中逻辑一致,并通过ThicknessHelper::FromLengths构造内边距,同样处理了 RTL 翻转。

响应状态变化:三个关键事件

要让自定义标题栏始终与系统状态同步,必须订阅以下事件(见 CustomTitleBar.xaml.cs):

void CustomTitleBar_Loaded(object sender, RoutedEventArgs e) { coreTitleBar.LayoutMetricsChanged += OnLayoutMetricsChanged; coreTitleBar.IsVisibleChanged += OnIsVisibleChanged; // The SizeChanged event is raised when the view enters or exits full screen mode. Window.Current.SizeChanged += OnWindowSizeChanged; UpdateLayoutMetrics(); UpdatePositionAndVisibility(); }
事件触发时机示例中的处理
CoreApplicationViewTitleBar.LayoutMetricsChanged标题栏布局指标变化(如高度、inset 变化)重新通知CoreTitleBarHeight/CoreTitleBarPadding绑定
CoreApplicationViewTitleBar.IsVisibleChanged标题栏可见性变化(全屏模式)重新计算标题栏的 Visibility 与所在行
Window.Current.SizeChanged窗口尺寸变化(进出全屏时触发)同上,重新定位标题栏

与之对应的CustomTitleBar_Unloaded中必须逐一注销事件(-=),避免悬挂引用导致泄漏。C++/WinRT 版本在 CustomTitleBar.cpp 中用revoker令牌(token)完成订阅与退订。

全屏模式下的布局策略

示例用两层 Grid 实现"普通模式标题栏占一行、全屏模式标题栏浮于内容之上"的效果。其注释给出了清晰的布局示意(CustomTitleBar.xaml.cs):

// When not in full screen mode, the grid looks like this: // Row 0: Custom-rendered title bar // Row 1: Rest of content // // In full screen mode, the the grid looks like this: // Row 0: (empty) // Row 1: Custom-rendered title bar // Row 1: Rest of content
void UpdatePositionAndVisibility() { if (ApplicationView.GetForCurrentView().IsFullScreenMode) { // In full screen mode, the title bar overlays the content. TitleBar.Visibility = coreTitleBar.IsVisible ? Visibility.Visible : Visibility.Collapsed; Grid.SetRow(TitleBar, 1); } else { // When not in full screen mode, the title bar is visible and does not overlay content. TitleBar.Visibility = Visibility.Visible; Grid.SetRow(TitleBar, 0); } }

场景二页面还提供全屏模式切换演示(Scenario2_Extend.xaml.cs):通过ApplicationView.GetForCurrentView().TryEnterFullScreenMode()进入全屏、ExitFullScreenMode()退出,并监听Window.Current.SizeChanged更新按钮图标与状态文本。

自定义标题栏的挂载:包装页面内容

MainPage.AddCustomTitleBar()(SampleConfiguration.cs)展示了正确的挂载方式:把页面原有内容摘出来塞进自定义标题栏控件的第二行,再把自定义标题栏整体设为窗口内容:

public void AddCustomTitleBar() { if (customTitleBar == null) { customTitleBar = new CustomTitleBar(); customTitleBar.EnableControlsInTitleBar(areControlsInTitleBar); UIElement mainContent = this.Content; this.Content = null; customTitleBar.SetPageContent(mainContent); this.Content = customTitleBar; } } public void RemoveCustomTitleBar() { if (customTitleBar != null) { this.Content = customTitleBar.SetPageContent(null); customTitleBar = null; } }

SetPageContent在RootGrid中维护内容元素并固定放置到第 1 行;C++/WinRT 对应实现见 CustomTitleBar.cpp。另外,C# 版本通过 Themes/Generic.xaml 为CustomTitleBar提供了默认控件模板,模板内仅是一个绑定背景/边框属性的 Border。

在标题栏中绘制控件:Window.SetTitleBar(仅 XAML)

标题栏区域默认会将所有鼠标点击视为"拖动窗口"操作,若要在其中放置 CheckBox 等交互控件,必须显式声明可拖动区域。示例通过Window.Current.SetTitleBar实现(CustomTitleBar.xaml.cs):

public void EnableControlsInTitleBar(bool enable) { if (enable) { TitleBarControl.Visibility = Visibility.Visible; // Clicks on the BackgroundElement will be treated as clicks on the title bar. Window.Current.SetTitleBar(BackgroundElement); } else { TitleBarControl.Visibility = Visibility.Collapsed; Window.Current.SetTitleBar(null); } }

要点:

  • SetTitleBar(BackgroundElement)把标题栏中的矩形背景指定为可拖动区域,同时该区域之外的标题栏元素(如 CheckBox)就可以正常接收点击。
  • 传入null则取消自定义拖动区域,恢复系统行为。
  • 该 API仅 XAML 应用可用(README 明确标注 "Drawing controls in the title bar (XAML only)"),C++/WinRT 版本的等价调用见 CustomTitleBar.cpp。

相关主题与延伸阅读

标题栏定制主要围绕以下两个 API 家族展开:

  • Windows.UI.ViewManagement.ApplicationView/ApplicationViewTitleBar:负责颜色定制与全屏模式管理(IsFullScreenMode、TryEnterFullScreenMode、ExitFullScreenMode)。
  • Windows.ApplicationModel.Core.CoreApplicationViewTitleBar:负责视图扩展、布局指标与状态事件(ExtendViewIntoTitleBar、Height、SystemOverlayLeftInset/RightInset、IsVisible、LayoutMetricsChanged、IsVisibleChanged)。

仓库中与本示例直接相关的资源:

  • FullScreenMode 示例:本示例 README 的 "Related samples" 中明确关联的姊妹示例,专门演示全屏模式 API,与场景二的全屏切换逻辑互相印证。
  • 原 README 还提及一个 JavaScript(WinJS)版本的 TitleBar 示例,该版本已归档,现仓库仅维护 C#、C++/CX 与 C++/WinRT 版本(分别位于 cs、cpp、cppwinrt 子目录)。

小结

TitleBar 示例完整覆盖了 UWP 标题栏定制的四种典型手法,从最简单的 12 个颜色属性配置,到视图扩展、状态事件响应,再到 XAML 专属的标题栏控件嵌入,是一个可以直接照搬的最小可用实现。实际项目中可按需组合:仅在品牌色要求下修改ApplicationViewTitleBar颜色;需要沉浸式界面时开启ExtendViewIntoTitleBar并配合CoreApplicationViewTitleBar的布局指标绘制自定义标题栏;同时务必留意 Alpha 通道规则与"功能随 Windows 10 版本逐步开放"的限制。

  • 示例工程

【免费下载链接】Windows-universal-samples

API samples for the Universal Windows Platform.

项目地址:https://gitcode.com/gh_mirrors/wi/Windows-universal-samples
点击查看免费下载

相关推荐

上一篇:Rustix终极指南:如何用安全系统调用封装库提升开发效率
下一篇:Git常用命令速查:Front-end-articles版本控制最佳实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询