一段时间以来,一个名为Prism Full App(.NET Core)的项目模板已添加到Prism的项目模板中。
使用这个项目模板,我认为开发Prism的人应该以这种方式创建项目,除非有任何限制,所以我将使用它。让我们查看并了解结构,并在创建项目时将其用作参考。
如果您对此配置感到满意,则最好使用此Prism Full App项目模板作为自己开发的起点。
让我们来看看。
现在,在
中基于Prism Full App(.NET Core)创建一个新项目。这次我创建了一个名为WpfSampleFullApp的项目。
只需创建此项目,就会创建6个项目,如下所示。
如果将
WpfSampleFullApp作为启动项目运行,则如下图所示,将启动一个外观类似于Hello world的应用程序。
生成的项目
在
中,我们将逐个查看每个项目。
WpfSampleFullApp项目
该项目将成为切入点。这非常简单,它只有一个App类以及一个MainWindow和MainWindowViewModel。
这里没有什么特别要说的。
让我们看看WpfSampleFullApp项目指的是什么。我指的是以下项目。
- WpfSampleFullApp.Core
- WpfSampleFullApp.modules.ModuleName
- WpfSampleFullApp.Services
- WpfsampleFullApp.Services.Interfaces
简而言之,就是那样。现在,让我们看看这个App类如何在DI容器中添加模块并注册类。 App.xaml.cs看起来像这样:
App.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | using Prism.Ioc; using WpfSampleFullApp.Views; using System.Windows; using Prism.Modularity; using WpfSampleFullApp.Modules.ModuleName; using WpfSampleFullApp.Services.Interfaces; using WpfSampleFullApp.Services; namespace WpfSampleFullApp { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterSingleton<IMessageService, MessageService>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<ModuleNameModule>(); } } } |
首先,让我们看一下CreateShell方法。这是不言而喻的,但是因为MainWindow是应用程序的外壳,所以它只是创建MainWindow的实例。
接下来,让我们看一下ConfigureModuleCatalog方法。您只需使用AddModule添加此项目模板生成的唯一模块项目。
最后,让我们看一下RegisterTypes。
在这里,它是WpfSampleFullApp.Services.Interfaces中定义的服务接口与WpfSampleFullApp.Services中定义的实现类之间的关联。它只是在DI容器中注册。
总而言之,此WpfSampleFullApp项目大致执行以下操作。
- 模块注册
- 链接服务接口和实现
- 创建主窗口
WpfSampleFullApp.Core项目
该项目是一个模块类,定义了每个人都使用的通用类。这是一个不依赖其他项目的项目。并且定义了以下类。
- RegionNames类
- Mvvm / ViewModelBase类
- Mvvm / RegionViewModelBase类
RegionNames类
这只是一个常量,用于定义MainWindow中定义的Region的名称。我在过渡到屏幕时指定Region的名称,但此处将其定义为常量,以便不进行硬编码,并由其他项目引用。
定义新的区域后,在此处添加名称作为常量。
Mvvm / ViewModelBase类
从BindableBase继承并实现IDestructible接口的几乎为空的类。
Mvvm / RegionViewModelBase类
顾名思义,这是设置为Region的ViewModel的基类。
它继承了ViewModelBase并实现了两个接口INavigationAware和IConfirmNavigationRequest。
由于在
区域中设置的ViewModel通常会编写与屏幕过渡有关的处理,因此通常会实现在屏幕过渡之前和之后提供回调的INavigationAware以及在屏幕过渡之前编写确认处理的IConfirmNavigationRequest接口。这是一个家伙,所以感觉就像我们在这里实现它并提供一个空的实现。
我想在此添加
例如,您将添加要显示为对话框的View的ViewModel基类。
之后,将在此处添加由EventAggregator交换的PubSubEvent的继承类。
WpfSampleFullApp.Services.Interfaces项目
感觉在这里定义了应用程序模型层中的服务。没有依赖它的项目。换句话说,它不依赖于棱镜。
简而言之,它是各种模块的ViewModel层中使用的接口的定义。因此,感觉就像仅定义了模型层提供给ViewModel的接口。
如果您的模型层提供了用例!如果看起来像这样,它将类似于WpfSampleFullApp.UseCases.Interfaces。
其余的是在其他项目中进行混合还是定义的一条细线,但是如果它是一个定义由模型层(而不是模型层)提供的接口的项目,则由访问DB或WebAPI的类实现的Repository系统接口也将在此处定义。至于上下文,它不是从数据库中看到的上下文的接口,例如GetAll,GetById,Update,Save,而是定义了模型需要从外部资源在上下文中命名的接口的位置。
默认情况下,定义了仅提供消息的IMessageService接口。
WpfSampleFullApp.Services项目
这定义了WpfSampleFullApp.Services.Interfaces项目中定义的服务接口的实现类。这也不取决于棱镜。只有一个MessageService。
引用的项目是WpfSampleFullApp.Services.Interfaces项目。
感觉就像模型层的核心逻辑就在这里。
WpfSampleFullApp.Modules.ModuleName项目
这是定义View和ViewModel的模块项目。这是一个令人失望的项目名称ModuleName,因此您可能要删除它并根据Prism Module(.NET Core)项目模板重新创建它。
点在于,它仅取决于WpfSampleApp.Modules.Services.Interfaces项目,而不取决于WpfSampleApp.Modules.Services项目。关键是依赖性是接口,而不是实现。
只有WpfSampleFullApp项目知道
实现和接口关联。
让我们放在一起
表示依赖性是这样的。
让我们调用Web API
它不如Web API大,但我想通过Web获取消息。
具体来说,应该显示从以下URL返回的JSON的message属性,而不是当前显示的Message Service中的Hello。
https://raw.githubusercontent.com/runceel/mockapi/master/message.json
返回的JSON
message.json
1 2 3 | { "message": "Hello from GitHub" } |
您可以直接在MessageService中使用HttpClient编写该过程,但是它不利于测试,因此让我们为外部资源访问创建一个Repository层。
在WpfSampleFullApp.SErvices.Interfaces项目中为存储库定义以下接口。
储存库/IMessageRepostory.cs
1 2 3 4 5 6 7 8 9 | using System.Threading.Tasks; namespace WpfSampleFullApp.Services.Interfaces.Repositories { public interface IMessageRepository { ValueTask<string> GetMessageAsync(); } } |
IMessageService也将是异步的,因此我们也对其进行更改。
IMessageService.cs
1 2 3 4 5 6 7 8 9 | using System.Threading.Tasks; namespace WpfSampleFullApp.Services.Interfaces { public interface IMessageService { ValueTask<string> GetMessageAsync(); } } |
我重写了
模块项目的ViewAViewModel类,以执行以下操作:我认为我不会在构造函数中读取很多数据,但是这次是这样,因此我在进行最少代码更改的情况下进行了以下工作。
ViewAViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using WpfSampleFullApp.Core.Mvvm; using WpfSampleFullApp.Services.Interfaces; using Prism.Regions; using System.Threading.Tasks; namespace WpfSampleFullApp.Modules.ModuleName.ViewModels { public class ViewAViewModel : RegionViewModelBase { private string _message; public string Message { get { return _message; } set { SetProperty(ref _message, value); } } public ViewAViewModel(IRegionManager regionManager, IMessageService messageService) : base(regionManager) { Message = "Loading..."; messageService.GetMessageAsync().AsTask().ContinueWith(x => { Message = x.Result; // エラーはとりあえず考えない }); } public override void OnNavigatedTo(NavigationContext navigationContext) { //do something } } } |
然后创建一个名为WpfSampleFullApp.Repositories的项目,并添加对WpfSampleFullApp.Services.Interfaces项目的引用。现在让我们实现IMessageRepository。让我们添加对System.Text.Json的引用并快速实现它。
MessageRepository.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | using System; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; using WpfSampleFullApp.Services.Interfaces.Repositories; namespace WpfSampleFullApp.Repositories { public class MessageRepository : IMessageRepository { private readonly HttpClient _httpClient; public MessageRepository(HttpClient httpClient) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); } public async ValueTask<string> GetMessageAsync() { using var jsonStream = await _httpClient.GetStreamAsync( "https://raw.githubusercontent.com/runceel/mockapi/master/message.json"); var result = await JsonSerializer.DeserializeAsync<MessageResult>(jsonStream, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, } ); return result.Message; } } public class MessageResult { public string Message { get; set; } } } |
添加处理以将存储库类实现添加到App.xaml.cs中的DI容器中。不要忘记在WpfSampleFullApp项目中添加对WpfSampleFullApp.Repositories项目的引用。
App.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | using Prism.Ioc; using WpfSampleFullApp.Views; using System.Windows; using Prism.Modularity; using WpfSampleFullApp.Modules.ModuleName; using WpfSampleFullApp.Services.Interfaces; using WpfSampleFullApp.Services; using System.Net.Http; using WpfSampleFullApp.Services.Interfaces.Repositories; using WpfSampleFullApp.Repositories; namespace WpfSampleFullApp { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App { protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { // 以下 2 行を追加 containerRegistry.RegisterSingleton<HttpClient>(); containerRegistry.RegisterSingleton<IMessageRepository, MessageRepository>(); containerRegistry.RegisterSingleton<IMessageService, MessageService>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<ModuleNameModule>(); } } } |
如果到目前为止可以执行,请执行它。您应该会看到以下内容:
感觉很好。项目依赖项如下。
单元测试
默认情况下,将为模块创建单元测试项目。如果您还想测试与服务相关的项目,则最好根据需要为模型层添加一个单元测试项目。
摘要
Prism Full App(.NET Core)我查看了项目模板并添加了一些处理程序,但是我个人认为基于此模板添加各种内容很容易。是的
我刚刚对项目模板所吐出的代码进行了一些处理,但是目前,此代码已发布在GitHub上。
https://github.com/runceel/WpfSampleFullApp