架构
架构
本节提供有关UI中涉及的类层次结构的信息。它涵盖了大多数主要子系统,并描述了它们如何交互。
BaseClasses.png依赖对象
有关DependencyObject功能的完整描述,请参见Dependency System Overview。
视觉效果
由于DependencyObject提供了一种存储数据的方式,因此下一步是将像素绘制到屏幕上。Visual类提供了构建可视对象树的方法,每个可视对象都包含绘图指令和有关如何呈现这些指令(剪切,转换等)的元数据。Visual的设计是极其轻便和灵活的,因此大多数功能都不会公开API,并且严重依赖于受保护的回调函数。
视觉是用户世界和Renderer系统之间的连接点。
Noesis GUI框架通过遍历Renderer管理的数据结构来显示数据。这些称为渲染节点的结构表示一个分层的显示树,每个节点上都有渲染指令。该树只能通过消息传递协议访问。在编程时,您将创建Visual元素和派生类型,这些元素通过此消息传递协议在内部与渲染树进行通信。
这里有一个非常重要的建筑细节需要注意,整个视觉树和绘图指令都被缓存。在图形方面,我们使用保留的渲染系统。这使系统能够以高刷新率重绘,而渲染系统不会阻塞对用户代码的回调。这有助于防止出现无响应的应用程序。
图中没有真正注意到的另一个重要细节是系统实际执行合成的方式。
Noesis GUI框架使用“画家的算法”绘画模型。这意味着,不是剪辑每个组件,而是要求每个组件从显示器的背面到正面进行渲染。这允许每个组件在上一个组件的显示上绘画。此模型的优点是可以具有复杂的部分透明的形状。使用当今的现代图形硬件,此模型相对较快。
核心理念是转向更具声明性的“以属性为中心”的编程模型。在视觉系统中,这显示在几个有趣的地方。
首先,如果考虑保留模式图形系统,这实际上是从命令式DrawLine / DrawLine类型模型转移到面向数据的模型:new Line()/ new Line()。转向数据驱动的渲染后,可以使用属性来表达对绘图指令的复杂操作。从Drawing派生的类型实际上是用于渲染的对象模型。
其次,如果评估动画系统,您会发现它几乎是完全声明性的。无需要求开发人员计算下一个位置或下一个颜色,您可以将动画表示为动画对象上的一组属性。然后,这些动画可以表达开发人员或设计人员的意图(在5秒钟内将按钮从此处移至此处),然后系统可以确定实现此目的的最有效方法。
UIElement
UIElement定义了核心子系统,包括布局,输入和事件。
在许多系统中,要么有一组固定的布局模型(HTML支持三种布局模型;流,绝对和表),要么没有布局模型(仅支持绝对定位的模型)。Noesis GUI Framework假定开发人员和设计人员想要一个灵活的,可扩展的布局模型,该模型可以由属性值而不是命令式逻辑来驱动。在UIElement级别,引入了布局的基本协定:具有Measure和Arrange传递的两阶段模型。
度量允许组件确定要采用的大小。这是与安排不同的阶段,因为在许多情况下,父元素会要求孩子进行多次测量以确定其最佳位置和大小。父元素要求子元素进行度量的事实证明了另一个关键理念:从内容到大小。所有控件都支持将内容调整为自然大小的功能。这使本地化更加容易,并且允许在调整大小时动态地布局元素。安排阶段允许父母定位并确定每个孩子的最终尺寸。
每个输入事件通常都会转换为至少两个事件:“预览”事件和实际事件。Noesis GUI Framework中的所有事件都有通过元素树进行路由的概念。如果事件从目标沿树向上遍历到根,则事件被称为“泡沫”;如果事件从根开始并向下遍历至目标,则事件被称为“隧道”。输入预览事件通道,使树中的任何元素都有机会过滤或对该事件采取操作。然后,常规(非预览)事件从目标一直冒到根。
为了更进一步,UIElement还引入了CommandBindings的概念。命令系统允许开发人员根据命令端点(实现ICommand的东西)定义功能。命令绑定使元素可以定义输入手势(Ctrl + N)和命令(新建)之间的映射。输入手势和命令定义都是可扩展的,并且可以在使用时连接在一起。例如,这使得最终用户可以自定义他们想要在应用程序中使用的键绑定变得微不足道。
框架元素
可以用两种不同的方式查看FrameworkElement。它在较低层中引入的子系统上引入了一组策略和自定义项。它还引入了一组新的子系统。
FrameworkElement引入的主要策略是围绕应用程序布局。FrameworkElement建立在UIElement引入的基本布局协定的基础上,并添加了布局“插槽”的概念,这使布局作者更容易拥有一组一致的属性驱动布局语义。诸如HorizontalAlignment,VerticalAlignment,MinWidth和Margin(仅举几例)之类的属性,使所有从FrameworkElement派生的组件在布局容器内部具有一致的行为。
FrameworkElement引入的两个最关键的内容是数据绑定和样式。
数据绑定子系统是一种简单的方式,用于表示您希望将给定元素中的一个或多个属性绑定到一条数据。Noesis GUI Framework完全支持属性绑定。数据绑定最有趣的功能之一就是引入了数据模板。数据模板使您可以声明性地指定应如何可视化一条数据。您可以创建问题,然后让数据确定将要创建的显示,而不是创建可以绑定到数据的自定义用户界面。
样式实际上是数据绑定的一种轻量级形式。使用样式,可以将一组属性从共享定义绑定到一个或多个元素实例。通过显式引用(通过设置Style属性)或通过将样式与元素的类型相关联来隐式地将样式应用于元素。
控制
Control的最重要功能是模板。复制允许控件以参数化的声明方式描述其呈现。一个控件模板是真的无非一个脚本来创建一组子元素,以绑定到通过控制所提供的属性。
控件提供了一组股票属性,Foreground,Background,Padding,仅举几例,模板作者随后可以使用这些属性来自定义控件的显示。控件的实现提供了数据模型和交互模型。交互模型定义了一组命令(如关闭窗口)和绑定到输入手势(如单击窗口上角的红色X)。数据模型提供了一组属性,以自定义交互模型或自定义显示(由模板确定)。
通过在数据模型(属性),交互模型(命令和事件)和显示模型(模板)之间进行拆分,可以完全自定义控件的外观和行为。
控件数据模型的一个常见方面是内容模型。如果查看类似Button的控件,您将看到它具有对象类型的名为“ Content”的属性。该属性通常是字符串,但是会限制您可以在按钮中放置的内容类型。按钮的内容可以是简单的字符串,复杂的数据对象或整个元素树。对于数据对象,数据模板用于构造显示。
内容控件
内容控件只是被限制为包含单个项目的控件。ContentControl的Content属性通常用于指定呈现控件时显示在控件内部的信息。例如,按钮的内容是显示按钮时出现在按钮内部的文本,图像或其他元素。Content属性同时支持文本和UIElement内容。因为内容控件的单个项目可以是任何任意对象,所以控件可以包含潜在的大对象树。只能有一个直子。
除了Content之外,ContentControl类的另一个有趣的成员是boolean HasContent属性。如果Content为null,则仅返回false,否则返回true。
ItemsControl
定义一个控件,该控件可以包含无限制的项目集合,而不仅仅是一个内容。ItemsControl将其内容存储在Items属性中。每个项目都可以是一个任意对象,默认情况下,它就像在内容控件中一样被呈现。
Items属性是只读的。这意味着您可以将对象添加到最初为空的集合中,也可以删除对象,但是不能将Items指向完全不同的集合。ItemsControl具有一个单独的属性,该属性支持使用称为ItemsSource的现有任意集合填充其项目。
除了这些属性之外,ItemsControl的其他有趣成员还包括HasItems属性(一个只读的boolean属性,可以轻松地从声明性XAML对控件的空状态进行操作)和DisplayMemberPath属性(可以设置为一个字符串属性)。每个项目(或更复杂的表达式)上的属性名称,该属性会更改每个对象的呈现方式。
面板
它是所有布局容器的基类。它使用UIElement对象的集合将其内容存储在Children属性中。
装饰器
另一个容器基类,但具有单个Child内容。