比较 Windows 窗体设计器框架与 WPF 设计器框架
更新:2007 年 11 月
WPF 设计器体系结构与 Windows 窗体设计器体系结构差别很大,后者以 IComponent 接口和 System.ComponentModel 命名空间为特征。如果已经创建过 Windows 窗体控件的自定义设计时实现,您将注意到 WPF 设计器体系结构更易于使用和扩展。
WPF 设计器体系结构保留了 Windows 窗体设计器对象模型中的 TypeConverter 和 TypeDescriptor 类。但 WPF 设计器体系结构的多数其他方面是不同的。有关 Windows 窗体设计时体系结构的更多信息,请参见扩展设计时支持。
ComponentModel 框架和 WPF 框架之间的主要差异
下表汇总了 WPF 设计器体系结构和 System.ComponentModel 框架之间的差异。
ComponentModel 框架 |
WPF 设计器框架 |
---|---|
基于 IComponent、IContainer 和 ISite 接口。 |
基于 FrameworkElement 类。 |
依赖宿主提供的设计时服务。 |
设计器以声明方式发布最低要求。 |
每个控件类型都有专用的设计器类型。 |
任意数量的功能可以在一个控件类型上运行。 |
元数据针对每个控件类型进行硬编码;在控件的编译时修复。 |
元数据部署在单独的程序集内;可以自定义或由工具替换。这样便可以独立于控件更新设计时元数据。 |
IDesignerHost 保留设计器状态。 |
EditingContext 类保留设计器状态。 |
服务被收集并与 IServiceContainer 实现共享。 |
EditingContext 类保留服务引用。 |
BehaviorService 管理键盘、鼠标和命令交互。 |
WPF 设计器工具体系结构管理键盘、鼠标和命令交互。 |
编辑对象模型包括运行时控件,可通过 PropertyDescriptor 类进行后期绑定访问。 |
编辑对象模型提供一个间接层使运行时控件抽象化。类别编辑器允许编辑单个 UI 内的多个属性。 |
IComponent 与 FrameworkElement
WPF 元素派生自 FrameworkElement 类,该类在 WPF 核心服务与框架级元素类之间提供连接。
WPF 元素不实现 IComponent 接口。这是 WPF 设计器不使用 System.ComponentModel 框架的重要原因之一。这意味着 WPF 控件从未就位。因此 WPF 控件无法请求 System.ComponentModel 设计环境中的设计器服务。
设计时服务
System.ComponentModel 框架中的设计器请求设计环境中的服务。在 WPF 设计器框架中,您不需要查询环境来获得服务便可以完成大多数任务。
在 System.ComponentModel 框架中,不能保证设计器宿主中存在设计器服务,这表示在调用 GetService 方法以后自定义设计器代码必须始终检查是否存在 null 引用。当服务不存在时设计器代码必须完全降低级别,而在多数情况下这种约束无法得到满足。
在 WPF 设计器框架中,自定义设计器以声明方式发布其最低要求。如果宿主无法满足协定,则设计器不会加载。这使得整体实现更加简便、更加可靠。
专用设计器类型和分离元数据
在 System.ComponentModel 框架中,设计器类型通过 DesignerAttribute 元数据属性与其相应的组件相关联。这表示在编译时建立关系,并在组件的运行时和设计时行为之间强制形成硬编码的依赖关系。若要附加不同的设计器,您必须更改 DesignerAttribute 声明并重新编译组件的基本代码。
在 WPF 设计器中,设计器元数据包含在一个单独的程序集内,将其与运行时实现真正地分离。这种自由度意味着不同的工具可以为相同的运行时类型提供完全不同的设计体验。有关更多信息,请参见元数据存储区。
编辑对象模型
在 System.ComponentModel 框架中,自定义设计器通过 PropertyDescriptor 类以后期绑定方式访问控件。此规则不是由设计环境强制执行的,并且如果开发人员忘记通过 PropertyDescriptor 类访问控件则会产生 Bug。
在 WPF 设计器框架中,自定义设计器通过一个编辑对象模型与运行时控件交互。此模型提供一个可使控件抽象化为模型和视图的间接层。此对象模型消除了通过 PropertyDescriptor 类访问控件的必要。
与 ComponentModel 设计器框架的相似处
编辑上下文是 WPF 设计器的基础。EditingContext 类包含有关设计器的上下文状态。
编辑上下文在概念上类似于 System.ComponentModel.Design 命名空间中的 IDesignerHost 接口。IDesignerHost 接口定义其接口中的许多功能,而 EditingContext 类仅注重数据和行为功能。
编辑上下文公开服务的方式与 IServiceContainer 接口类似。编辑上下文支持枚举,但不支持在添加服务后将服务移除。有关更多信息,请参见编辑上下文体系结构。
属性用法方面的差异
设计器属性在 WPF 设计器体系结构和 Windows 窗体体系结构中有着不同的含义。下表描述了在这两种框架之间与设计器相关的属性用法有何不同。
属性 |
“Windows 窗体属性”窗口 |
“WPF 设计器属性”窗口和 Expression Blend 属性检查器 |
---|---|---|
指定将传递给属性的值,以使该属性从另一个来源获取其值。这称为“环境”。 |
不可用 |
|
指定某一属性或事件是否应在“属性”窗口中显示。 |
指定某一属性或事件是否应在“属性”窗口中显示。对通常不显示的某个属性显式设置为 true 时,该属性将显示。 |
|
指定当属性或事件显示在一个设置为“按分类顺序”模式的 PropertyGrid 控件中时,用于对属性或事件分组的类别的名称。 |
指定当属性显示在“属性”窗口中时对属性进行分组的类别的名称。 |
|
指定属性的默认值。 |
对于 CLR 数据类型,指定属性的默认值。对依赖项属性忽略。 |
|
指定属性或事件的说明。 |
不可用 |
|
为属性、事件或不接受参数的 public void 方法指定显示名称。 |
为此属性 (Attribute) 所应用于的属性 (Property) 指定将要在“属性”窗口中显示的名称。 |
|
指定用于更改属性的编辑器。 |
指定用于更改属性的编辑器,包括多属性类别编辑器。 |
|
不可用 |
EditorBrowsableState.Advanced 将类别编辑器或属性放入“高级”展开器中。 |
|
指定类或成员的上下文关键字。 |
不可用 |
|
指定是否应本地化某一属性。 |
不可用 |
|
指示对象的文本表示形式由星号等字符遮盖。 |
不可用 |
|
指定此属性 (Attribute) 所绑定到的属性 (Property) 在设计时是只读的还是可读/写的。 |
指定此属性 (Attribute) 所绑定到的属性 (Property) 在设计时是只读的还是可读/写的。使用 ReadOnlyAttribute 标记的属性将在属性检查器中向字符串编辑器显示只读对象。 |
|
指示在关联属性值更改时应刷新“属性”窗口。 |
不可用 |
|
指定对于此属性绑定到的对象要使用哪种类型作为转换器。 |
指定对于此属性绑定到的对象要使用哪种类型作为转换器。 |
|
指定组件的默认事件。 |
指定组件的默认事件,该事件决定在双击时要创建的事件处理程序。 |
|
指定组件的默认属性。 |
指定组件的默认属性,该属性决定默认情况下选择哪个属性。 |
|
指定用于为组件实现设计时服务的类。 |
不可用 |
|
为属于某一类别的类指定设计器。 |
不可用 |
|
表示工具箱项的属性。 |
不可用 |
|
为工具箱指定要使用的筛选器字符串和筛选器类型。 |
不可用 |
|
不可用 |
用于在检查某个程序集中有无要添加到工具箱中的类型时阻止类型在工具箱中显示。 |
|
不可用 |
用于指定要添加到集合编辑器或子属性编辑器的组合框中的项。允许指定用于自定义创建的工厂。 |
|
不可用 |
用于指定属性将在“属性”窗口中的显示顺序。 |
下列属性在 WPF 设计器框架中使用,但不能在 Windows 窗体设计器框架中使用。
指定工具箱图标方面的差异
在 Windows 窗体设计器框架中,可以通过向控件类应用 ToolboxBitmapAttribute 为自定义控件指定工具箱图标。
在 WPF 设计器框架中,可使用嵌入资源和命名约定指定工具箱位图。此外,还可以使用 ToolboxBrowsableAttribute 限制程序集中的哪些类型可用于填充工具箱。
指定元数据方面的差异
在 Windows 窗体中,将通过应用 DesignerAttribute 等属性以声明方式指定设计器元数据。
在 WPF 设计器体系结构中,设计器元数据在元数据存储区中指定。有关更多信息,请参见元数据存储区。