原文 UWP 扩展/自定义标题栏的方法,一些概念和一些注意事项

在 Windows 10 的前几个版本中将页面内容扩展到标题栏上还算简单,主要是没什么坑。直到一些新控件的引入和一些外观设计趋势变化之后,扩展标题栏开始出现一些坑了。

本文将重温 UWP 自定义标题栏或者扩展标题栏的方法,但更重要的是解决一些坑。


扩展/自定义标题栏

要扩展标题栏,只需要拿到 CoreApplicationView 的实例,然后设置 TitleBar 的 ExtendViewIntoTitleBar 属性为 true 即可。

var applicationView = CoreApplication.GetCurrentView();
applicationView.TitleBar.ExtendViewIntoTitleBar = true;

要自定义标题栏,只需要拿到 ApplicationView 的实例,然后设置 TitleBar 里各种属性接口。

var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.BackgroundColor = Colors.Khaki;
titleBar.ButtonBackgroundColor = Colors.Transparent;

一些概念

那么问题来了,为什么前者需要拿到 CoreApplicationView 的实例,后者需要拿到 ApplicationView 的实例?它们到底是什么区别?

我在 CoreApplication/Application、CoreWindow/Window 之间的区别 一文中提到过 CoreApplication、CoreWindow 和 CoreDispatcher 之间的关系。继续借用那篇文章中的图:

其中,Window 是对 CoreWindow 的封装,提供了更多与 XAML 相关的功能。这里的 ApplicationView 也是这样,是对 CoreApplication 的封装,提供了 XAML 相关的功能。

那篇文章中详细描述了这几个概念之间的关系和区别。考虑到阅读的一致性,我摘抄过来:

具体来说,CoreWindow 是与操作系统、与整个应用打交道的类型,提供了诸如窗口的尺寸、位置、输入状态等设置或调用;Window 是与应用内 UI 打交道的类型,比如可以设置窗口内显示的 UI,设置内部哪个控件属于标题栏,获取此窗口内的 Compositor。与之对应的,CoreApplicationView 是应用与操作系统交互,与窗口消息循环机制协同工作的类型,包含窗口客户区和非客户区设置;ApplicationView 也是与应用内 UI 打交道的类型,它可以使用 XAML 相关的类型对应用程序视图进行更方便的设置。

总结起来,CoreWindow 和 CoreApplicationView 提供更加核心的操作系统或应用底层功能,而 Window 和 ApplicationView 对前者进行了封装,使得我们能够使用 Windows.UI.Xaml 命名空间下的类型对窗口和应用视图进行控制。

于是,我们便能够理解为什么扩展标题栏和设置标题栏颜色会使用到两个不一样的类型了。

ExtendViewIntoTitleBar 是改变了窗口的客户区(Client Area)和非客户区(Non-client Area)组成,这是传统 Win32 编程中的概念,是更接近操作系统底层的概念。BackgroundColor 和 ButtonBackgroundColor 这里需要用到 Windows.UI.Xaml 命名空间中的颜色,而 CoreApplicationView 太底层,无法使用 XAML 颜色。

一些坑

控件在标题栏区域无法交互

想必当你扩展到标题栏后,在标题栏区域增加一些按钮的时候,肯定会遇到下面的情况:


▲ 按钮在标题栏区域的一半无法交互

这显然是无法接受的。

然而,当我们将一个 XAML 控件指定为标题栏之后,就只会是那个控件所在的区域响应标题栏操作,其他地方就会恢复正常。

// TitleBar 是我在 XAML 中写的一个 x:Name="TitleBar" 的控件。
Window.Current.SetTitleBar(TitleBar);


▲ 按钮在标题栏区域现在可以交互了

特别说明一下,SetTitleBar 传入的是 UIElement 类型的实例,也就是说这也是 XAML 交互的一部分。我们需要使用 Window 的实例,而不是 CoreWindow 的实例。

更高的标题栏,或者被遮挡

如果被指定为标题栏的控件更大,超出标题栏区域了,它还会成为标题栏吗?如果被其他控件遮挡了,它还会响应标题栏事件吗?

实际看来,无论它多大,都能响应标题栏事件;但被遮挡的部分就真的被遮挡了,没有标题栏响应。


▲ 更高的标题栏,或者被遮挡

事实上,指定为标题栏的控件可以在界面的任何地方,不需要一定在顶部。只不过,绝大多数不作死的应用都不会这样设置吧!

在什么时机调用?

扩展标题栏用的是 CoreApplicationView,自定义标题栏颜色用的是 ApplicationView,将控件指定为标题栏用的是 Window。如果我们的应用只有一个视图,其实我们随便找一个初始化的地方调用就好了。但如果我们的应用有多个视图,那么给非主要视图调用的时候就需要在其初始化之后了。阅读 理解 UWP 视图的概念,让 UWP 应用显示多个窗口(多视图) 了解如何编写多个视图的 UWP 应用,了解非主要视图的初始化时机。

当然,如果你比较极客,从 Main 函数开始写 UWP 应用,就像我在 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 一文中做的一样,那么你也需要等到初始化完毕之后才能调用(至少是 SetWindow 之后了)。

适配移动设备

移动设备上并不是标题栏,而是状态了和虚拟按键。关于扩展视图到这些区域,可以阅读 win10 uwp 标题栏 - 林德熙。


参考资料

本文会经常更新,请阅读原文: https://walterlv.com/post/tips-for-customize-uwp-title-bar.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

UWP 扩展/自定义标题栏的方法,一些概念和一些注意事项的更多相关文章

  1. List<T>直接充当Combox控件DataSource并扩展自定义记录的方法

    一般认为List只有转换为DataTable后才能充当CombBox的数据源,其实不然: List<SYS_COMMANDS> comdList = _menuMan.Load(c =&g ...

  2. CI框架扩展自定义控制器的方法

    扩展CI中的控制器 有时需要对CI中的控制器作统一操作,如进行登录和权限验证,这时就可以通过扩展CI控制器来实现. 扩展CI控制器只需要在application/core文件夹中建一个继承自CI_Co ...

  3. UWP中实现自定义标题栏

    UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...

  4. 双击CAD对象(具有扩展数据),显示自定义对话框实现方法

    转自:Cad人生 链接:http://www.cnblogs.com/cadlife/p/3463337.html 题目:双击CAD对象,显示自定义对话框实现方法 内容粘贴如下: 主要是绑定两个事件: ...

  5. 【Win10开发】自定义标题栏

    UWP 现在已经可以自定义标题栏了,毕竟看灰色时间长了也会厌烦,开发者们还是希望能够将自己的UI做的更加漂亮,更加与众不同.那么废话不多说,我们开始吧! 首先要了解ApplicationViewTit ...

  6. [置顶] xamarin android自定义标题栏(自定义属性、回调事件)

    自定义控件的基本要求 这篇文章就当是自定义控件入门,看了几篇android关于自定义控件的文章,了解了一下,android自定义控件主要有3种方式: 自绘控件:继承View类,所展示的内容在OnDra ...

  7. 基于electron+vue+element构建项目模板之【自定义标题栏&右键菜单项篇】

    1.概述 开发平台OS:windows 开发平台IDE:vs code 本篇章将介绍自定义标题栏和右键菜单项,基于electron现有版本安全性的建议,此次的改造中主进程和渲染进程彼此语境隔离,通过预 ...

  8. WPF 自定义标题栏 自定义菜单栏

    自定义标题栏 自定义列表,可以直接修改WPF中的ListBox模板,也用这样类似的效果.但是ListBox是不能设置默认选中状态的. 而我们需要一些复杂的UI效果,还是直接自定义控件来的快 GitHu ...

  9. Android开发-取消程序标题栏或自定义标题栏

    注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 在Android开发中,跟据需要我们有时候需要自定义应用程序的标题栏或者取消程序的标题栏,下面本菜鸟在此记录与分享一下自己使用的方法 ...

随机推荐

  1. SQL Server 2008 Tempdb 数据库迁移

    1.首先检查数据文件位置及名称 SELECT name,physical_name FROM sys.database_files 2.迁移 USE master; GO ALTER DATABASE ...

  2. 辛星笔记之高质量JavaScript代码书写要点

    首先本文章是http://www.zhangxinxu.com/wordpress/?p=1173 的读书笔记,读者能够自己到鑫旭的空间去阅读原文.这里我对其进行了简化. 可维护的代码的一些要求: ( ...

  3. 4、linux开发中常用指令

    1.cat /proc/device 可以查看各个全部字符设备和块设备,在register_chrdev中设置的名字在打印出来的信息中可以看到:2.top 可以看各个应用程序占用CPU量及PID等信息 ...

  4. 从Ecipse中导出程序至apk 分类: H1_ANDROID 2013-10-26 22:17 516人阅读 评论(0) 收藏

    若未有数字证书: 1. 2. 3. 4. 5. 若已有数字证书: 上面的后3步改为 版权声明:本文为博主原创文章,未经博主允许不得转载.

  5. 设置UIButton的文字显示位置、字体的大小、字体的颜色

    btn.frame = CGRectMake(x, y, width, height); [btn setTitle: @"search" forState: UIControlS ...

  6. 9个完整android开源app项目

    一.photoup 介绍: photoup 是一款开源的相册类app,主要功能是将本地图片提交到facebook上去,虽然他的功能和facebook的远程服务相关,但是本身是可以被当作一款 相册应用的 ...

  7. css 水平垂直居中的方法总结

    在项目中经常会遇到设置元素水平垂直居中的需求.而且具体的场景也不同,所以将个人总结的方法做个汇总,希望对浏览者有用. 以下所举的例子都以一个html为准,这里规定好一些公用样式. body { bac ...

  8. 【u020】Couple number

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 任何一个整数N都能表示成另外两个整数a和b的平方差吗?如果能,那么这个数N就叫做Couple numb ...

  9. [Angular] Observable.catch error handling in Angular

    import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import 'rxjs/add/opera ...

  10. linux使用.rpm包安装mysql

    一:下载mysql的.rpm安装包 点击链接查看下载教程:点击打开链接 二:创建目录,上传文件 创建mysql目录:# mkdir mysql 进入目录:# cd mysql 将下载好的MySQL-s ...