简单的 Prism 应用程序模板






4.83/5 (11投票s)
VS2008 模板,用于创建简单的基于 Prism 的 WPF 应用程序。
引言
本文介绍了一套我编写的模板,旨在帮助创建基于 Prism 库的简单 WPF 应用程序,该应用程序基于 Composite WPF 框架。为什么要在已有模板(例如 Calcium)的情况下编写这些模板?这是一个非常合理的问题。原因有很多。
您有多少次需要在工作或在家中创建简单的应用程序?这可能是一个您正在创建的小型实用程序、一个用于证明新功能/概念的原型应用程序,或者仅仅是一些用于试验 Prism 等的代码。您知道您想使用 Prism 库来构建它,但说实话,您也知道从头开始设置一个 Prism 应用程序,连接 Shell、基础设施和模块,将花费比您打算花费在创建实际应用程序上的时间还要多。当然,您可以直接使用一个现有的基于 Prism 的应用程序(如果您有一个的话),然后删除您不需要的部分,但这通常不是一个干净的解决方案。当您使用现有的 Prism 框架(例如 Calcium)时,情况也是如此。
我需要一些 VSTemplates,它们能够让我快速创建基于 Prism 的应用程序,并且具有通用的格式,例如 Shell、Infrastructure 和 Modules,我可以快速创建并快速实例化它们,从而使我能够专注于手头的任务。对我来说,重要的是它们使用 Prism 的基本功能,而无需任何修改。我不想仅仅为了创建我的简单应用程序而学习一个框架之上的框架。我从网上阅读和学习到的关于 Prism 的内容应该可以直接使用。我还希望能够添加自动连接到自身的其他模块,并能够灵活地向默认 Shell 添加新区域。
本文介绍的两个 VSTemplates 恰恰提供了这些功能。我绝不会将这些模板与 Calcium 提供的专业模板相提并论。但我新的模板使我能够快速创建具有标准架构的简单应用程序。它们也有助于培训和向新人们介绍 Prism 概念,使他们能够轻松地进行原型设计/测试应用程序。
尽管我在创建这些模板时尝试纳入了许多最佳实践,但我采取了一种实用的方法,并非所有人都支持。例如,创建的 MVVP 模块确实引用了视图。尽管示例中没有一个为了更传统的 MVVM 而使用它,但如果您的简单应用程序需要,它就在那里。
本文中的模板包含了一些随着时间从不同来源收集的代码,供开发人员在需要时使用。我只尝试包含我在过去创建简单应用程序时发现有用的实用程序。我已添加了这些代码原始位置的引用,并在本文末尾添加了作者的引用。
主要特点
本节提供了新模板功能的简要概述。下面是您创建并执行新解决方案时默认生成的解决方案的图片。
简单 Prism 解决方案
选择“简单 Prism 解决方案”模板并生成解决方案后,Visual Studio 将加载一个完整的可编译解决方案。生成的解决方案使用了 Prism 网站示例中的标准布局,例如,包含 Shell、Infrastructure 和 Module 项目。编译时,输出将被写入到单个 bin 目录。该目录的布局可以直接复制,并且在不修改任何代码或配置文件的情况下运行生成的应用程序。
自动链接 MVVM 视图
MVVMView 旨在用于将新的 MVVM 模块添加到 Prism 解决方案的 modules 文件夹中。它创建一个新的模块项目,该项目的输出会自动链接到 CompositeWPF 应用程序中。实现基于 MVVM 模式。它默认提供了一些有用的功能,例如,自动将 DataContext 挂钩到 ViewModel,并通过扩展通用基类来提供对 Logger、UnityContainer 等关键对象的引用。
集成 Log4Net 日志记录
在我们的组织中,强制要求 Log4Net 作为 .NET 应用程序中日志记录的默认组件。提供的解决方案已用 Log4Net 日志记录覆盖了默认的日志记录实现。一些已包含的组件默认使用 Log4Net。使用 Log4net 作为默认日志记录器可确保这些组件中提供的日志记录能够自动集成。默认的 Log4Net 配置为将日志记录到控制台、UDP 输出(供 Chainsaw 使用)以及滚动文件。
聚合计时器服务
聚合计时器 (Consolidated Timer) 是一种简单的低分辨率计时器设施,它允许单个 Windows Timer 实例处理应用程序中的许多计时器操作,从而减少需要维护的系统计时器资源数量。基础计时器每秒检查一次计时器,因此这是一个非常粗粒度的计时器设施,适用于许多 GUI 任务,例如刷新、轮询等。
集成对话框
我包含了 CompositeWPF Contrib 提供的 Dialogs Workspace,以便可以随时使用。
等待光标支持
此功能允许模块激活 Shell 上的等待光标。
简单菜单
这里没什么特别的,只是一个简单的菜单工具栏,其中实现了几个基本命令来执行基本功能,例如退出应用程序。
示例用法
包含了一个示例模块,演示了如何根据需要使用上述所有功能。通常,此项目会被删除,并替换为使用 MVVMView 模板生成的模块。
模板安装
关于高级信息就到这里,我们来谈谈模板的安装。它提供了一个 MSI 安装程序,执行后将安装模板和所有必需的库。我仅在 Visual Studio 2008 上测试了这些模板。
第三方库
我们目前的开发使用了一些对所有应用程序开发都很常见的第三方库。我们使用的库列表如下所示
- Prism Composite Application Library DLLs v2.0.0.0
- Log4Net DLL v1.2.10.0
- NUnit Framework DLLs v2.5.0
- MOQ DLLs v3.1.0.0
这些组件本来可以安装在 GAC 中,但我更倾向于将它们放在每个开发人员计算机上的固定位置。因此,安装程序会将它们放置在 C:/Program Files/DotNetLibraries。并非所有这些库目前都在框架中使用,但都包含在内,以方便开发人员。我打算在某个时候更新框架以集成这些工具。
模板文件
安装会将模板文件放置在用户 MyDocuments 文件夹下的“Visual Studio 2008 /Templates/ProjectTemplates”。模板配置为在选择“新建项目”对话框的“我的模板”Visual C# 部分显示。两个新模板是“Simple Composite WPF Solution”和“MVVMView”。这两个模板及其用途将在下面介绍。
简单 Prism 解决方案模板
选择此模板将创建一个新的 Prism 解决方案。我已尽力使此解决方案的内容尽可能实用,并遵循许多 Composite WPF 应用程序使用的传统布局。
我假设安装是在 32 位机器上进行的。如果不是,则需要将上述库复制到正确的 Program Files/DotNetLibraries 目录。其次,如果您更改了 Visual Studio 读取模板的位置,则需要相应地重新定位上述模板。
此模板生成的解决方案布局如下所示
正如您所看到的,此解决方案有三个部分:Shell、Infrastructure 和 Modules。
基础结构
Infrastructure 项目是 Prism 应用程序的公共区域,我用它来存储应用程序可能需要的任何通用伪影。Infrastructure 分为以下几个部分。在 Prism 框架中使用时,在 Infrastructure 类中存储通用实体是一个常见的模式,我发现它对中小型应用程序最有用,这就是我将其用于模板的原因。对于大型应用程序,我倾向于将通用数据存储在 Core 类中,每个模块一个。
CommonEntities
本节包含应用程序中使用的通用实体类。默认情况下,有两个:TimerJob.cs 和 ApplicationConfig.cs。当您阅读下面对应的服务时,这些类是不言自明的。
CompositeWPFBase
CompositeWPFBase 部分中有三个默认类:BindableObject
、DispatchedObservableCollection
和 CompositeWPFBase
。BindableObject
是 Josh Smith 的一个类。这是 INotifyPropertyChanged
接口的实现,我用它来设置 ViewModel 中的数据绑定。所以我将其添加到基类中以求简便,正如他所建议的。阅读他的文章以获取更多信息。
CompositeWPFBase
类是我用于所有 MVVM 类的基类。它公开了指向基类核心组件的多个引用,例如 Entity Container、Event Aggregator 和 ILoggerFacade
。这个通用类用于连接我的 MVVM 模式。通常,用户无需直接访问这两个基类。
包含 DispatchedObservableCollection
是为了解决 ObservableCollection
无法用于数据绑定,当集合在非主 GUI 线程的任何线程上更新时的问题。DispatchedObservableCollection
实现由 WPFExtensions 库提供。由于我不需要该库的其他功能,因此我已将 DispatchedObservableCollection
类直接包含在 Infrastructure 项目中。
配置
本节包含应用程序使用的配置对象。有一个名为 RegionConstants
的类。该类包含 Shell 和 Module 组件中使用的区域的定义。如果开发人员决定修改 Shell 并添加新区域,则需要在该类中添加区域的定义。
此部分还定义了许多 Composite Presentation Events,这些事件在应用程序中跨越使用,例如 StatusBarMessageEvent
、WaitCursorEnabledEvent
等。
接口
本节包含应用程序使用的通用接口定义。
服务
Services 部分是我定义用于在应用程序中使用的通用服务的地方。默认情况下,我提供两种服务:第一种是 CompositeWPFTimerService,第二种是 Configuration Service。
CompositeWPFTimerService
此服务是一种低分辨率计时器服务(默认 1 秒)。其理念是,您无需在应用程序中使用多个计时器操作来执行通用的计时器操作,而是可以向此服务注册 TimerJob
以供处理。计时器作业存储在队列中,并根据 TimerJob 规范进行处理。此服务支持以下计时器基础操作
public interface ICompositeWPFTimerService
{
void Start();
void Stop();
void AddJob(TimerJob job);
void RemoveJob(string name);
void UpdateJob(TimerJob job);
void RemoveAllJobs();
void PauseJob(string name);
void ResumeJob(string name);
}
用户在 TimerJob
实例本身中指定每个 TimerJob
如何处理。每个作业都必须有一个唯一的名称。用户可以定义计时器是一次性计时器,还是在过期后应重新安排。用户可以指定计时器应执行的时间以及作业应重新安排时的重置时间。用户指定作业在时间段到期后应执行的 JobTask
。这将在每个任务的单独线程上执行。
public string Name { get; set; }
public DateTime ExecutionTime { get; set; }
public TimeSpan ResetDuration { get; set; }
public TimerJobState State { get; set; }
public JobTask Operation { get; set; }
public TimerType OneShot { get; set; }
一点需要注意的是,此功能中有大量的 Log4Net 调试信息,默认开启。要将其关闭,请在 Shell 的 app.config 文件中添加以下内容
<logger name="CompositeWPFTimerService">
<level value="OFF" />
</logger>
ConfigurationService
Configuration Service 仍在开发中。当前实现是一个使用“Settings”功能读取和写入用户首选项的简单示例,这对于我的简单应用程序来说已经足够。但是,通过这个简单的抽象,该服务可以很容易地修改以使用替代的存储介质,如果需要的话。
Workspaces
由于 Composite WPF 本身不支持对话框,因此我借此机会集成了 CompositeWPF Contrib 中的 DialogWorkspace。我在这段代码上遇到了一些问题,因为我找不到如何正确地定位对话框,所以我修改了代码,使其始终将对话框居中显示在屏幕中央。
Prism Shell
Shell 是应用程序的主入口点。除了常见的 WPF 伪影(如 app.xml 等)之外,它还包含 Prism 特定的组件,例如 Bootstrapper.cs 等。
主应用程序 Shell
此应用程序的主 Shell 定义了三个区域:MainMenu、StatusBar 和一个 StatusBar 区域。这是使用 Composite WPF 的小型应用程序的最低配置。遵循标准的 Composite WPF 文档,开发人员可以轻松地在 Shell 中添加其他区域,用于 GUI 的其他区域,例如工具栏、选择区域等。
模块
Modules 部分是存储模块的地方。这些模块托管在 Shell 容器中。默认情况下,默认解决方案中提供了四个模块。所有模块都遵循前面讨论的相同的 MVVM 设计模式。
MainMenu 模块
主菜单模块提供了一个基本菜单,如下所示。它预先连接了“退出”和“关于”对话框,以演示 Dialog Workspace 的使用。
StatusBar 模块
屏幕底部的状态栏使用 Event Aggregator 订阅要显示的消息。模块可以发布将在状态栏中显示的消息。
Dialogs 模块
此模块托管应用程序使用的对话框。这些对话框使用前面讨论的 Composite WPF Contrib 中的 Dialog Workspace。
MVVM 项目
我创建了第二个模板,为添加到应用程序的每个新模块创建一个新项目。这里的想法是,用户将为应用程序所需的每个模块将模块添加到 Modules 解决方案中。当用户选择 MVVMProject 模板并执行它时,将创建一个具有以下结构的新项目
从上面的示例可以看出,模板使用用户提供的名称重命名模板中的所有伪影,在这种情况下,所有项目文件都以前缀“TestProject”命名。它还使用相同的名称重命名命名空间和类名等;请参见下方
模板创建了集成模块到解决方案所需的所有基础架构。项目被自动配置为将输出的 DLL 复制到输出模块目录,以便在运行时自动拾取。模块被自动配置为填充 DisplayRegion。如果用户需要更改此位置,他们只需要修改 TestModule 部分中区域的常量,如上所示。
目标是让开发人员只需向用户控件和 ViewModel 类添加代码来填充业务特定代码,而无需过多担心 Prism。此外,视图 ViewModel 的基类提供了对日志记录、事件聚合器和 Unity 组件的轻松访问。
用法
模板的使用非常简单。应用程序的主屏幕如下所示
创建 Prism 解决方案
请按照以下步骤创建新的 Prism 解决方案
- 启动 Visual Studio
- 选择“文件 - 新建项目”选项
- 在“我的模板”选择中选择 SimplePrismSolution 选项
- 选择解决方案的位置,然后单击“确定”
- 解决方案将创建,并且可以进行构建和编译
添加模块
使用以下步骤创建模块
- 在继续之前,通常会从生成的解决方案中删除 Examples 模块。
- 选择“文件 - 新建项目”选项。
- 在“我的模板”选择中选择 MVVMModule 选项。
- 在文件夹位置选择中选择 Modules 目录的位置,以确保模块位于 Modules 位置下,然后单击“确定”。
- 将创建一个新模块,并且可以进行构建和编译。
运行示例模块
本节简要概述了示例模块。示例模块显示了一个带标签的视图,其中包含多个基本选项卡,提供了展示如何使用某些功能的工具。
状态栏示例
在文本框中输入文本。选择按钮,文本将在状态栏中显示 3 秒。
Timer 示例
此示例使用户可以玩转计时器。您可以添加和操作计时器,并在提供的窗口中查看输出。
配置服务示例
这个简单的应用程序展示了如何访问和使用配置服务。
日志记录示例
此应用程序演示了如何访问日志记录器并将不同的日志记录消息写入 Log4Net 输出。
等待光标示例
此应用程序演示了如何启用和禁用应用程序等待光标。
摘要
与所有此类任务一样,这仍然是一个进行中的工作。目的是继续升级和添加这些简单的模板。我非常欢迎对此代码的反馈,以帮助我不断学习和进步。
参考文献
这些模板中的许多库和代码是我多年来收集的有用的实用程序等的集合。本节是对这些贡献的参考,没有它们,我的生活将变得更加艰难。
- BindableObject by Josh Smith: http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/
- WPF Extensions for the
DispatchedObservableCollection
: http://wpfextensions.codeplex.com/ - Composite WPF Contrib for the Dialog Workspace: http://www.codeplex.com/CompositeWPFContrib
- Prism for the Composite WPF: http://www.codeplex.com/CompositeWPF
历史
- V1.0: 模板的初始版本 2010 年 1 月 19 日。