闲话少说,书归正传:
1 Metro C++程序的入口点:
C++开发的Metro程序有两种架构:Windows RT和Direct程序,这两种程序可以完美的进行交互,用一个不恰当的例子形容他们之间的关系应该就是 MFC和Win32 API程序之间的关系。Windows RT是将Windows API封装在了一组类库中,从用户角度来说它处于更高层次,当然受到的局限性也更大,它的入口点被封装在IDE(vs2011)自动生成的app类中,该类被manifest指定为入口点。而Direct程序更像是用Win32 API开发的窗口程序,它的入口点是我们熟悉的main()。我们首先要实现两个类分别继承于IFramworkView和IFramwordViewSource,然后在main函数中创建IFrameworkViewSource接口实例,用该实例作为参数调用静态方法CoreApplication::Run(),并在IFrameworkViewSource接口的CreateView方法中创建IframeworkView实例,并调用IFrameworkView接口实例相关的方法(由自己实现)启动程序。
2 Metro UI:
紧接上文,使用 Windows RT开发的应用程序其实就是.Net程序的变种,通过 XAML定义Ui布局,使用丰富的控件可以进行比较简便快捷的开发出绚丽夺目的软件。但是它同样具备一些缺点:对效率的要求比较低,不够灵活只能使用控件提供的功能,无法访问一些底层的API,对于有特定需求的开发者(系统级软件)无法访问底层的API。另外,对于习惯了直接使用Win32开发窗口程序的程序员来说不容易适应。相反,Direct程序就是对Win32窗口程序的一种延伸,你可以自由创建或者获得CoreWindow这种对象(类似于窗口句柄),并在CoreWindow上直接使用Direct函数绘制(取代Gdi和GDI+)。同时你还可以使用dispatcher/event传递消息(取代message机制)。使用WRT直接使用Com组建,以及一些列Windows为Metro保留或者重新开发的Win32 API。然而,Direct程序开发复杂,难度大,繁琐的API调用必定会延长开发周期,因此究竟如何选择还需要根据实际情况而定。
对于我来说,我选择两者混用,在交互方面微软做的还是非常好的,基本是无缝对接。
3 进程与UI(题外话):
Windows程序通常分为两部分:进程和UI。当然,这么说非常不准确,事实上我想表达的意思其实是进程未必一定是要有UI的,即便没有UI程序依然也可以执行。因此,如果我们想真正弄懂Metro的机制,必须区分开进程与UI。特别值得一提的是,我们必须清楚地知道永远是进程驾驭UI,而非UI左右进程。这句话的意思并非是在UI中不能创建进程,而是说我们必须把进程作为程序的核心,我们需要UI的时候就去 创建,当UI不存在的时候,不意味进程就结束了,依然可以做我们想做的事,在需要的时候还可以再创建UI。当然,如果你只想开发一个WinRT程序,也未必要理解这些,就好像很多未曾深入研究的MFC程序员,它们觉得窗口就是和程序共存的(同生同灭),这个不难理解,因为窗口不是自己创建(微软帮你做了大部分工作)的,你要做的就是在UI中添代码,或许对你来有一种错觉就是现有UI后有进程。。。有了上面的一些不成熟的见解,我要引出的是几个类CoreApplication,CoreApplicationView,CoreWindow。这几个类表示的是什么?其实CoreApplication表示的就是进程,CoreWindow表示的是UI(类似于窗口句柄),CoreApplicaitonView就是将CoreWindow和CoreApplication联系起来的对象。对应到Windows窗口程序,CoreApplication就是表示执行main函数的一个进程,CoreWindow就是在这个进程中创建的一个窗口。由于Metro程序本质上就是一个拥有一个主窗口的全屏程序,因此需要使用CoreApplicationView将这个进程和一个主窗口绑定。通过CoreApplication::GetCurrentView获得当前进程的绑定关系CoreApplicationView,再通过CoreApplicationView::CoreWindow属性就可以找到绑定到当前进程的主窗口对象CoreWindow。
4 WinRT UI 结构:
承接上文,Metro程序的Ui其实都是基于一个全屏主窗口创建的。WinRT和MFC,WPF或者C#一样强化了UI而淡化了非UI部分,使得写程序看似就是一个在UI框架中填代码的操作,其实这么看也无可厚非,还能简化程序开发的难度。我们就看一看,到底使用 XAML创建的Ui是一个什么结构?这里首先要提到一个类Windows::UI::Xaml::Window。这个东西究竟是什么?从MSDN上看"A Window object is just surfacing information from CoreWindow, which in turn is referencing the window created by the system."这个我研究了很久,一直没明白,有几点是我感觉到值得特别注意的:
1 )这个类有获取CoreWindow的方法,但是却找不到任何从CoreWindow获取Window的方法。
2 )它属于Xaml空间
3 )它与UIElement有关系,我们之前说了MetroUI都是基于一个CoreWindow上的,但是从CoreWIndow我并没有找到与UI有什么关系。
通过以上几点我可以大胆推测:Window就是主窗口的CoreWindow的一个XAML表现形式,它将作为所有UIElment的父窗口。这样一来,CoreWindow就和UIElement挂钩了。之所以说它只表示主窗口的CoreWindow,是因为我们无法从任意的CoreWindow获得Window,而只能从一个Window类的静态属性Current得到唯一的Window对象,这只可能是主窗口的Window。
通过不断地实验,我大致可以得出Metro的Ui结构,一个CoreApplication绑定一个CoreWindow,这个CoreWIndow作为所有UIElement的父控件的表现形式就是Window。Window的Content属性是Frame,一个Window对应n个Frame也就是软件可以有很多场景,每个frame绑定n个page,这个page也就是你当前页面下所有控件的父节点。你可以在一个场景中自由切换页面,也可以在Window下自由切换场景,这对游戏开发者有着非凡的意义。对于一般非游戏开发者,可能一个frame多个page的情况比较常见。
5 page切换:
使用frame的Navigate()函数或者GoBack(),GoForward()。后两个函数没什么可说的,像浏览器一样,可以根据你的切换历史,跳转到指定页面。值得一题的是Navigate函数,很奇怪,它的参数并不是指定页面对象的名字,反而是指定页面的类型名。我大胆推测一下吧,在Metro程序中我们没有显式的创建过页面,而系统自动创建了我们自定义的页面,和可能是我们每一个自定义的页面类型只会被创建唯一一个实例,而且我们并不是使用ref new来创建,而是通过navigate函数创建这唯一的实例,因此我们只要指定页面的类型就可以跳转到唯一的页面。不过这只是我的推测。