【Win 10 应用开发】UI Composition 札记(一):视图框架的实现
在开始今天的内容之前,老周先说一个问题,这个问题记得以前有人提过的。
设置 Windows.ApplicationModel.Core.CoreApplicationView.TitleBar.ExtendViewIntoTitleBar 属性可以让应用窗口中的内容扩展到标题栏。简单地说,就是你的UI区域可以扩大,并填充到标题栏,这在开发自定义标题栏或弄个什么毛玻璃效果时很有用。
不过,这个 ExtendViewIntoTitleBar 属性有个“八阿哥”,一旦你设置之后,系统会对其进行记录,很难还原回默认的窗口标题栏。这是为啥呢,这个问题其实老周早已找到答案,只是写博客的时睺没有写出来,要是单独写这个内容,好像也太单调了。
今天忽然想起,就在本文中顺便说一下吧。
其实这个标题栏状态是保存在注册表中的,路径在
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ApplicationFrame\TitleBar\<你的应用程序包ID>
解决方法就是你找到这个键,然后在 TitleBar 下面找到你的应用ID,再把你的应用ID键删除就可以了。注意,这个TitleBar子键默认是不会出现的,只有当前用户安装过自定义了标题栏的应用后才会由系统创建。
===================================================================
好,以上内容完结,如果你在自定义标题栏时遇到问题,可以参考上述方法,当然,那是针对 UWP 应用的,桌面应用无需理会,也不受这个影响。
从今天开始,老周给大伙伴们讲一个不少朋友觉得很复杂的内容——UI Composition 。这个我不知道怎么翻译,干脆用原词了,当然你可以翻译为“用户界面构件”,或者“用户界面组建”,反正怪怪的。
这个玩意儿在开发的时候还是挺有用的,尤其是处理图像,或做一些界面效果时,还是蛮不错,有时候反而比 WPF 中的方便,当然,WPF 中有 Render 方法重写,UWP中没有。所以要借助 Composition 。
要在 UWP 中绘图,要么你直接用 XAML 的类型去组建 UI 树,要么你用 D2D,但这个是要用 C++ 去写的,也确实挺复杂的,尤其是像老周这种对 Direct Show 不熟悉的菜鸟来说,那就更难了。
如果你使用 Composition API 进行绘图或实现滤镜功能,除了 SDK 中的内容,你还应该借助一个组件—— Win 2D,这个东东对 D2D 做了封装,用起来很简单,经常可以与 Composition 结合使用。这个东东也是微软发布的,在项目中右击“引用”,然后从右键菜单中选择【Nuget 管理器】,然后你搜索 Win 2D,看到有.uwp 字样的你就安装即可。
UI Composition 很复杂吗?其实也不一定,我们可以抽丝剥茧,许多东西,不要一下子就往很复杂的方向上想,也不要想得太多,不然是学不明白的。只要把其结构搞清楚,后面就好进入状态了,一旦进入状态,你两个小时就能学会。
关于 UI Composition 的结构,本篇先不讲,咱们留到下一篇再讲,因为我们得先了解一下应用程序的视图框架。当然了,这个东西,在常规的应用程序中是用不到的,可能在游戏或者Direct相关的程序中会用到,不过啊,我们了解一下也是好的。
具体说来,我们要实现两个接口。
a、IFrameworkView:这是组装界面的重要类,在实现这个接口时,可以完成UI的组装,也可以处理应用窗口与用户的各种交互,比如键盘输入、鼠标或其他指针设备操作等。该接口提供了与生命周期相关的一些方法,我们通过实现这些方法来完成应用逻辑的。
b、IFrameworkViewSource:实现这个接口,只需要实现一个方法即可:
IFrameworkView CreateView()
这个方法会返回一个实现了 IFrameworkView接口的对象实例。
所以,实现 IFrameworkView 接口是核心,然后通过 IFrameworkViewSource 接口的 CreateView 方法把应用视图返回。
下面,我们来完成一个简单的例子,一边动手一边学习,效果可以提升 120 倍,信不信由你。
在VS中新建一个空白的应用程序项目。待项目新建完成后,你可以把项目生成的App.xaml、MainPage.xaml 以及相关的代码文件删除,因为本示例中我们用不上。

清单文件还是留着吧,不必删。
现在,我们新建一个代码文件,然后实现自己的应用视图类。
public class MyCustView : IFrameworkView
{
public void Initialize(CoreApplicationView applicationView)
{ } public void SetWindow(CoreWindow window)
{ } public void Load(string entryPoint)
{ } public void Run()
{ } public void Uninitialize()
{ }
}
我们看到,即将要实现的几个方法。
* Initialize:在初始化时调用,在这个方法中,可以实例化一些要用的类型或资源。
* SetWindow:在该方法中可以对应用窗口做相应处理,比如,你要跟踪用户鼠标指针的坐标,就可以在这里附加 PointerMoved 事件的处理方法,比如你要跟踪窗口大小(可以动态重绘界面元素),可以处理 SizeChanged 事件。
* Load:在应用程序开始执行之前加载一些外部资源,或者加载一些文件数据之类的。注意,这个方法会接收一个字符串参数,它是要调用的应用类型的入口点。在标准的基于 XAML 的应用程序中,一般是 App 类。这个值来自清单文件的配置,如没有特殊需要,可以忽略该参数。
* Run:这个时候,应用程序就开始执行了,消息循环也启动。
* Uninitialize:应用结束时会调用这个方法,所以,在这个方法里面可以做一些清理工作。
那么,这几个方法的调用顺序如何呢?很简单,我们写一些调试代码跟踪一下就明白了。
public class MyCustView : IFrameworkView
{
public void Initialize(CoreApplicationView applicationView)
{
Debug.WriteLine($"-- 正在调用 {nameof(Initialize)} 方法。");
} public void SetWindow(CoreWindow window)
{
Debug.WriteLine($"-- 正在调用 {nameof(SetWindow)} 方法。");
} public void Load(string entryPoint)
{
Debug.WriteLine($"-- 正在调用 {nameof(Load)} 方法。");
} public void Run()
{
Debug.WriteLine($"-- 正在调用 {nameof(Run)} 方法。");
} public void Uninitialize()
{
Debug.WriteLine($"-- 正在调用 {nameof(Uninitialize)} 方法。");
}
}
别急着运行,现在应用程序是无法运行的,我们还有一个接口没有实现。
public class MyCustViewSource : IFrameworkViewSource
{
public IFrameworkView CreateView()
{
return new MyCustView();
}
}
在实现 CreateView 方法时,返回刚刚上面定义的那个视图类的实例。
好,现在该实现的接口都实现了,但是,很遗憾,应用还是无法运行的。我且问你,Windows 上,要执行一个应用程序,首先要找到什么位置?对啊,入口点,也就是 Main 方法。UWP 应用也是一样的,你得有 Main 方法才行。其实基于XAML 的标准应用程序也是有 Main 方法的,只是它由开发工具帮你生成了。
因此,我们还要为应用程序写一个入口点,这个 Main 方法如果你觉得另起一类来写麻烦,你可以直接写到刚刚上面的 MyCustViewSource 类里面。不过,老周向来的习惯都是会单独写一个类来放 Main 方法的,因为那样代码看起来更明了。
class Program
{
static void Main(string[] args)
{
CoreApplication.Run(new MyCustViewSource());
}
}
这其实也很像我们以前写 WinForm 和 WPF 应用程序,在 Main 方法中会调用 Application.Run 方法。这里我们调用的是 CoreApplication 类的方法,它需要的参数正是一个实现了 IFrameworkViewSource 接口的类型实例。所以我们前面才要写 MyCustViewSource类,就是在这个地方用的。
经过上面这一番练习,你会了解到实现应用视图框架的过程:实现 IFrameworkView 接口编写核心应用代码 ---> 实现 IFrameworkViewSource 接口以返回视图实例 ---> 再把 source 实例传给 Run 方法来执行(在 Main 方法中)。
现在,你可以运行了,你会发现,应用窗口并没有出现,然后就结束了。那是因为实现 IFrameworkView 接口时,Run 方法中并没有启动任何消息循环,所以,应用程序运行后收不到任何消息,自然就结束了。
现在,我们看看”输出“窗口中的内容。

从结果中可知,应用程序先进行初始化,然后设置窗口参数,接着加载相关资源,随后开始执行,等到退出时再用 Uninitialize 方法去清理。
为了让大伙能看到窗口,我们在 Run 方法执行时启动一下消息循环。
public class MyCustView : IFrameworkView
{
CoreWindow theWindow = null;
public void Initialize(CoreApplicationView applicationView)
{
Debug.WriteLine($"-- 正在调用 {nameof(Initialize)} 方法。");
} public void SetWindow(CoreWindow window)
{
Debug.WriteLine($"-- 正在调用 {nameof(SetWindow)} 方法。");
theWindow = window;
} public void Load(string entryPoint)
{
Debug.WriteLine($"-- 正在调用 {nameof(Load)} 方法。");
} public void Run()
{
Debug.WriteLine($"-- 正在调用 {nameof(Run)} 方法。");
theWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);
} public void Uninitialize()
{
Debug.WriteLine($"-- 正在调用 {nameof(Uninitialize)} 方法。");
}
}
UWP 应用传统了 WPF 的优良传统,也是由 Dispatcher 对象来负责消息调度的,所以我常说,WPF能学好,UWP基本可以旁通。
现在,我们再运行一下,就能看到窗口了,而且它会等待你关闭了窗口,应用才会退出。

有大伙伴会问,怎么只有个初始屏幕?那当然了,因为这窗口是空白的,应用只是启动了消息循环,却没有任何界面元素,当然只能看到初始屏幕了。
至于说怎么组建 UI 元素,咱们下一篇再讨论吧,今天就写到这里,别写太长了,学习要一点点积累。
【Win 10 应用开发】UI Composition 札记(一):视图框架的实现的更多相关文章
- 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成
除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...
- 【Win 10 应用开发】UI Composition 札记(二):基本构件
在上一篇中,老周用一个示例,演示了框架视图的创建过程,在本篇中,老周将给大伙伴们说一下 Composition 构建 UI 的一些“零件”. UI Composition 有一个核心类——对,就是 C ...
- 【Win 10 应用开发】UI Composition 札记(四):绘制图形
使用 Win 2D 组件,就可以很轻松地绘制各种图形,哪怕你没有 D2D 相关基础,也不必写很复杂的 C++ 代码. 先来说说如何获取 Win 2D 组件.很简单,创建 UWP 应用项目后,你打开“解 ...
- 【Win 10 应用开发】UI Composition 札记(五):灯光
UI Composition 除了能够为 UI 元素建立三维空间外,还有相当重要的一个部件——灯光.宇宙万物的精彩缤纷,皆源于光明,光,使我们看到各种东西,除了黑洞之外的世界都是五彩斑谰的.故而,真要 ...
- 【Win 10 应用开发】UI Composition 札记(六):动画
动画在 XAML 中也有,而且基本上与 WPF 中的用法一样.不过,在 UWP 中,动画还有一种表现方式—— 通过 UI Composition 来创建. 基于 UI Composition 的动画, ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- 【Win 10应用开发】认识一下UAP项目
Windows 10 SDK预览版需要10030以上版本号的Win 10预览版系统才能使用.之前我安装的9926的系统,然后安装VS 2015 CTP 6,再装Win 10 SDK,但是在新建项目后, ...
- 【Win 10 应用开发】在代码中加载文本资源
记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...
- 【Win 10 应用开发】导入.pfx证书
这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...
随机推荐
- WebService的简单介绍与入门使用
WebService是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式 ...
- 翻译 | 一行 JavaScript 代码的逆向工程
原文地址:Reverse Engineering One Line of JavaScript 原文作者:Alex Kras 译者:李波 校对者:冬青.小萝卜 几个月前,我看到一个邮件问:有没有人可以 ...
- MySql join on 和 where
原文:http://www.cnblogs.com/Jessy/p/3525419.html left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录. right join : ...
- vue组件初学--弹射小球
1. 定义每个弹射的小球组件( ocicle ) 2. 组件message自定义属性存放小球初始信息(可修改) { top: "0px", //小球距离上方坐标 left: &qu ...
- 通过express搭建自己的服务器
前言 为了模拟项目上线,我们就需要一个服务器去提供API给我们调用数据.这次我采用express框架去写API接口.所有请求都是通过ajax请求去请求服务器来返回数据.第一次用node写后端,基本就是 ...
- GitHub Desktop客户端打开文件乱码问题解决方案
今天在使用GitHub Desktop客户端的时候,发添加本地仓库后文件内容显示为乱码. 1.现象 如下图所示: 2.原因分析 后来分析得知原来是由于编码不统一造成 的. 具体来说,我在window ...
- 糖果大战 hdu1204
糖果大战 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- margin:0px auto和text-align:center区别
(1)margin:0px auto :作用于块级元素,对块级元素进行居中 (2)text-align:center:作用于内联元素,必须放在要居中的内联元素所在的块级元素. 例: (1) <d ...
- Linux用户和文件权限管理
本文为原创文章,转载请标明出处 目录 用户管理 系统用户文件 添加用户 useradd 设置用户密码 passwd 删除用户 userdel 用户管理 usermod 用户组管理 系统用户组文件 添加 ...
- Python实战之IO多路复用select的详细简单练习
IO多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. select 它通过一个select()系统调用来 ...