什么是Xaml
Xaml(Extensible Application Markup Language) 可扩展应用程序标记语言,该语言基于xml实现的进行了相应的扩展。该语言很容易进行扩展,有点类似B/S编程中的代码后置,前端是HTML,后台是业务逻辑和相关处理代码。
还有一点是我们反复强调的,XAML并不是HTML。尽管XAML在元素的声明、程序样式的设置和指定事件处理程序上都和HTML非常类似,但是XAML是基于XML的,它是WPF的外在表现形式。而HTML主是一种标记语言,仅仅是用来为浏览器呈现页面内容。XAML除了用来呈现信息和请求用户输入等基本的功能外,它还包含了一些高级的特性,例如它提供了对动画和3D众多方面的支持。
xaml语言,微软提供了可视化的设计工具blend。基于blend创建的的界面模型及效果,都可以存储或者转换为xaml格式的代码,这样就可以大大的提高了团队中的设计人员和开发人员之间的协作,减少了设计人员原型效果,开发人员无法实现,设计人员可以自行设计后,转换为xaml代码。
关于xaml更多的内容,可以参考维基百科或百度知道。
相关的简单说明如下:
image
对于熟悉XML的同仁,应该没有什么难理解的。
什么是路由事件
我们先来看看MSDN给出的定义:
功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。
实现定义:路由事件是一个 CLR 事件,可以由 RoutedEvent 类的实例提供支持并由 Windows Presentation Foundation (WPF) 事件系统来处理。
我们来解释下MSDN给出的定义:
1、传统方式:
image
对应的xaml代码和后台代码如下:
image
后台对于的处理如下:
image
当然采用如下的方式也是可行的。
image
image
后台代码修改为:
image
2、WPF的路由方式:
路由事件使用以下三个路由策略之一:
冒泡:针对事件源调用事件处理程序。路由事件随后会路由到后续的父元素,直到到达元素树的根。大多数路由事件都使用冒泡路由策略。冒泡路由事件通常用来报告来自不同控件或其他 UI 元素的输入或状态变化。
直接:只有源元素本身才有机会调用处理程序以进行响应。这与 Windows 窗体用于事件的“路由”相似。但是,与标准 CLR 事件不同的是,直接路由事件支持类处理(类处理将在下一节中介绍)而且可以由 EventSetter 和 EventTrigger 使用。
隧道:最初将在元素树的根处调用事件处理程序。随后,路由事件将朝着路由事件的源节点元素(即引发路由事件的元素)方向,沿路由线路传播到后续的子元素。在合成控件的过程中通常会使用或处理隧道路由事件,这样,就可以有意地禁止显示复合部件中的事件,或者将其替换为特定于整个控件的事件。在 WPF 中提供的输入事件通常是以隧道/冒泡对实现的。隧道事件有时又称作 Preview 事件,这是由隧道/冒泡对所使用的命名约定决定的。
在传统的方式中,我们必须对每个事件源进行事件处理绑定,如果我们新增加新的对象或者新的事件源,那么我们还需要添加新的绑定。而这一切在WPF,都被统一处理和考虑了,下面,我们以冒泡为例来简单说明。
image
冒泡的顺序
image
修改后台代码如下:
image
关于逻辑树与可视化树,我们这里解释下:
逻辑树:简单来说,就是我们从界面上来看 界面的可视化基本组成部分,这就构成了窗口的一个逻辑树。逻辑树始终存在于WPF的UI中,不管UI是用XAML编写还是用代码编写。WPF的每个方面(属性、事件、资源等等)都是依赖于逻辑树的
image
可视树:可视树基本上是逻辑树的一种扩展。逻辑树的每个结点都被分解为它们的核心视觉组件。逻辑树的结点对我们而言基本是一个黑盒。而可视树不同,它暴露了视觉的实现细节。下面是Visual Tree结构就表示了上面四行XAML代码的视觉树结构。
image
可视树,将界面组成的所有对象本身的内容进行了解析,例如button 按钮,他的内容,是有contentpresenter和textblock构成。
关于逻辑树和可视树的更多介绍,可参考MSDN的介绍。
我这里给出简单的获取逻辑树和可视树的代码:
image
都上WPF本身提供了一些方法。采用递归的方式。
我们接着上面的关于查看事件源的地方:
image
经过上面我们看到了,默认情况下,WPF的事件是采用冒泡的方式进行事件的传递的,那么我们如何采用其他的二种策略呢?
我们再来看下隧道事件,隧道事件的顺序如下:引用MSDN中的解释图:
输入事件的冒泡和隧道
事件的处理顺序如下所示:
针对根元素处理 PreviewMouseDown(隧道)。
针对中间元素 1 处理 PreviewMouseDown(隧道)。
针对源元素 2 处理 PreviewMouseDown(隧道)。
针对源元素 2 处理 MouseDown(冒泡)。
针对中间元素 1 处理 MouseDown(冒泡)。
针对根元素处理 MouseDown(冒泡)。
我们来验证下,我们以此处理所有的preview事件,看看是不是按照上面介绍的方式去处理的。
image
对应的后台代码如下:
image
运行,后查看输出结果:
image
与我们预期的一致。关于更多的路由事件,我们后面通过单独的章节来说明。
WPF基础控件
系统默认提供的基础控件:
image
image
有些由于自己也没有进行深入的使用,可能就不会介绍太详细。
关于控件的基本使用,会在后续进行深入的讨论和演示。
什么是依赖属性
DependencyProperty(依赖属性):Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能,这些服务通常统称为 WPF 属性系统。由 WPF 属性系统支持的属性称为依赖项属性。
WPF界面控件中的属性,都可以称作是依赖属性,通过依赖属性,我们能够实现viewModel与界面元素属性之间进行绑定。
依赖属性与我们平时说的属性有区别的。
1、传统的属性
image
这没啥好说的,就是我们针对对象进行了封装。
假设,我们有一个类,有很多的属性,而且,又被多个对象继承,我们知道继承的特性,那么肯定会有很多的属性,本身我们可能基本不适用,那么该属性,还是会被创建的时候实例化,那么有没有什么办法,我们减少这样的开销呢?WPF针对这样的情况提出了依赖属性的概念。
2、依赖属性:
查看其基本的声明和定义:在注释中描述:通过方法设置的属性,数据绑定,动画,样式等。
image
依赖属性就是自己自己没有值,通过Binding从数据源获得值,就是依赖在别人身上,拥有依赖属性的对象称为依赖对象。
我们来看看WPF控件的基本继承链
Object类:在.Net中所有类型的根类型
DispatcherObject类:WPF 中的大多数对象是从 DispatcherObject 派生的,这提供了用于处理并发和线程的基本构造。WPF 基于调度程序实现的消息系统。
DependencyObject类:表示一个参与依赖项属性系统的对象。
Visual类:为 WPF 中的呈现提供支持,其中包括命中测试、坐标转换和边界框计算。
UIElement 类: WPF 核心级实现的基类,该类建立在 Windows Presentation Foundation (WPF) 元素和基本表示特征基础上。
FrameworkElement 类:为 Windows Presentation Foundation (WPF) 元素提供 WPF 框架级属性集、事件集和方法集。此类表示附带的 WPF 框架级实现,它是基于由UIElement定义的 WPF 核心级 API 构建的。
Control类:表示 用户界面 (UI) 元素的基类,这些元素使用 ControlTemplate 来定义其外观。
ContentControl类:表示包含单项内容的控件。
ItemsControl类:表示一个可用于呈现项的集合的控件。
Decorator类:提供在单个子元素(如 Border 或 Viewbox)上或周围应用效果的元素的基类。PPT中鼠标滑过文本框后,出现边框
Image类:表示显示图像的控件。
MediaElement类:表示包含音频和/或视频的控件。自己封装一个视频播放器
Panel类:为所有 Panel 元素提供基类。使用 Panel 元素在 Windows Presentation Foundation (WPF) 应用程序中放置和排列子对象。
Sharp类:为 Ellipse、Polygon 和 Rectangle 之类的形状元素提供基类。
image
关于依赖属性的声明和更详细的内容,我们在后续的单独的章节中有更详尽的介绍。
几种应用依赖属性的场景:
希望可在样式中设置属性。
希望属性支持数据绑定。
希望可使用动态资源引用设置属性。
希望从元素树中的父元素自动继承属性值。
希望属性可进行动画处理。
希望属性系统在属性系统、环境或用户执行的操作或者读取并使用样式更改了属性以前的值时报告。
希望使用已建立的、WPF 进程也使用的元数据约定,例如报告更改属性值时是否要求布局系统重新编写元素的可视化对象。依赖对象创建时并不包含存储数据空间。WPF中必须使用依赖对象作为依赖属性的宿主。
后面的章节,我们会结合具体的案例,来说明如何使用依赖属性。