【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 ...
随机推荐
- Hibernate中的主键生成器generator
本文讲述Hibernate的generator属性的意义.Generator属性有7种class,本文简略描述了这7种class的意义和用法. [xhtml] view plaincopy <c ...
- 翻译连载 |《你不知道的JS》姊妹篇 |《JavaScript 轻量级函数式编程》- 引言&前言
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 译者团队(排名不分先后):阿希.blueken.brucec ...
- FZU 1919 -- K-way Merging sort(记忆化搜索)
题目链接 Problem Description As we all known, merge sort is an O(nlogn) comparison-based sorting algorit ...
- JS获取随机的16位十六进制的数
直接上代码: function getRamNumber(){ var result=''; for(var i=0;i<16;i++){ result+=Math.floor(Math.ran ...
- 云计算---OpenStack Neutron详解
简介: neutron是openstack核心项目之一,提供云计算环境下的虚拟网络功能 OpenStack网络(neutron)管理OpenStack环境中所有虚拟网络基础设施(VNI),物理网络基础 ...
- ASP.NET没有魔法——开篇-用VS创建一个ASP.NET Web程序
为什么写这一系列文章? 本系列文章基于ASP.NET MVC,在ASP.NET Core已经发布2.0版本,微服务漫天的今天为什么还写ASP.NET?. 答:虽然现在已经有ASP.NET Core并且 ...
- Python面试题之copy/deepcopy详解
copy和deepcopy有什么区别? http://blog.csdn.net/qq_32907349/article/details/52190796 http://iaman.actor/blo ...
- HDU2874 LCA Tarjan
不知道为什么_add2不能只用单方向呢...........调试了好多次,待我解决这个狗血问题 #include <iostream> #include <vector> #i ...
- slf4j+log4j在Java中实现日志记录
小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...
- 压缩SQLServer数据库日志的一个存储过程
use master --注意,此存储过程要建在master数据库中 go if exists (select * from dbo.sysobjects where id = object_id(N ...