参考自林政《深入理解Windows Phone8.1 UI控件编程》,仅仅是我个人的总结,不能做学习用。后面文章同。
1. XAML是什么就不解释了,其实它经编译器形成.g.cs文件
obj\Debug\*.g.cs
如果XAML中声明的控件有x:Name属性,则会在.g.cs文件中生成对应代码。此文件也定义了InitializeComponent方法,由页面类的构造方法调用。
并且它是成功编译后才生成的,而同目录下*.g.i.cs文件则是在XAML修改后就静态生成,可以用于VS的智能感知等功能。
XAML可使用XamlReader.Load动态加载,这样在程序运行中也可以按情况加载指定的XAML了
如:
string myButtonXaml = "这里是格式良好的XAML片段"; //注意转义和命名空间 Button myButton = XamlReader.Load(myButtonXaml) as Button;
不仅是控件,动画等其它XAML代码一样可以。
但这里格式良好的XAML必须是单个根元素,且必须指定某一默认的XML命名空间,通常是xmlns:="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2. XAML的树结构
XAML中创建的程序UI概念化为一个对象树(元素树),对象树可进一步分为逻辑树和可视化树。
逻辑树:直观根据控件父子关系构造生成的,在路由事件中将会按这样的层次结构来触发。
可视化树是XAML中可视化控件及其子控件组成的一个树形控件元素结构图。
对象树:XAML中的元素具有属性,则此元素就是对象树中的一个对象。而某对象的某属性如果也是一个对象,则它们在对象树中互为父子关系。
可视化树:将对象树编辑或筛选后的表现形式,其中的对象是具有呈现意义的对象(具有呈现意义,并不是指一定要在界面中显示出来),集成在控件中并不直接显示的对象也是可视化树里的元素。
至此可以确定WP中可视化对象的呈现顺序,从可视化树最顶层节点元素开始遍历,遍历方法类似二叉树的先序遍历。因此可视化元素的内容优先于其本身呈现。
VisualTreeHelper是一个静态帮助器类,提供可视化对象级别编程的低级功能。
应用举例:ListBox中封装了ScrollViewer,获取它就可以判断ListBox是否滚到底,从而实现分页加载。
3. 路由事件
路由事件有三种路由策略:
冒泡:从引发事件的对象元素子集冒泡到包含这些子集的父对象元素,出现的事件及数据一路报告给沿着事件路由的对象,直到达到根事件。
直接:只有源对象本身才能调用。
隧道:与冒泡相反。
WP中的事件要么遵循冒泡路由策略,要么不路由。
事件处理方法中,参数sender就是发送对象;e是事件参数,作为EventArgs或其子类的实例。
e的几个重要方面
OriginalSource属性:当事件冒泡时,sender不再是事件引发对象,而是正在调用的处理程序的对象。而OriginalSource都报告引发事件的原始对象。
Handled属性:是一个布尔值,当把值设置为true,意味着大多数路由事件处理程序将停止路由,表示路由事件处理完毕。并非所有路由事件都可使用这种方法停止。
可视化树外的路由事件:可视化树外的部分将不会通过父子关系捕获路由事件。如Popup控件,如果要处理Popup路由事件,则应将处理程序置于Popup内的特定UI元素上(而非Popup本身)。Popup本身永远不会接收路由事件。
4. 框架Frame和页面Page
一个WP程序有一个框架和多个页面,框架相当于包含这些页面的容器。当前Frame可通过Window.Current.Content获取。
Page的导航逻辑使用一个栈来管理,因为页面是先进后出。可以通过Frame.BackStack获取栈的项目。
5. UI线程
UI线程即主线程,仅存在一个。其它的线程为后台线程。应尽量保持UI线程的“轻量”,耗时操作应在后台线程中执行。
创建后台线程:
Task.Factory.StartNew(() => { //执行相关后台线程的操作 });
在后台线程中访问UI线程中的对象:
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => { //访问UI线程中的对象 });
如果无法获取到已经启动的UI元素,则要在后台线程中启动UI线程:
await Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => { //执行UI线程操作 });
如果使用SynchronizationContext,提供不带同步的自由线程上下文,可以针对不同的异步模型采取正确的行为:
SynchronizationContext context; context = SynchronizationContext.Current;
后台线程中就可以:
context.Post(async (s) => { //处理相关UI线程操作 }, null);