入门
Prism入门非常容易。遵循以下步骤,您将快速启动并运行一个模块化且易于维护的应用程序。
本指南假定您对WPF应用程序项目的结构有所了解,并且对C#也有一定的了解。如果您对模型-视图-视图模型(MVVM)模式比较熟悉也会有很大帮助,而且WPF很容易支持该模式。如果您并不了解以上内容,请考虑先花点时间对其进行一些研究。
安装Nuget包
首先在Visual Studio中创建一个全新的WPF应用程序。接下来是安装合适的nuget包。在使用哪个容器来管理依赖项这一点上,您需要做出一个选择。而在本文档中Unity将是选择的容器。请参见下面的列表。
Package | Container | Version |
---|---|---|
Prism.Unity | Unity | 5.11.1 |
Prism.DryIoc | DryIoc | 4.0.7 |
注意:无需显式安装任何其他依赖项。安装上述软件包之一还将负责安装容器的软件包以及共享的Prism软件包。
覆写现有的应用程序对象
入门的下一步是继承新创建的WPF项目中包含的Application对象。打开App.xaml
并将标准WPF Application类替换为Prism的```PrismApplication``类。
<prism:PrismApplication
x:Class="WpfApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
</Application.Resources>
</prism:PrismApplication>
在上面的代码片段中,请注意添加了第6行来定义命名空间,并且更新了App对象使其派生自PrismApplication
。接下来,打开app.xaml.cs
的代码文件并更新类定义。
不要忘记从
PrismApplication
标签中删除StartupUri
属性,否则您就会得到两个window实例。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Prism.Unity;
namespace WpfApp1
{
public partial class App : PrismApplication
{
}
}
在PrismApplication
中定义了一对必须首先实现的抽象方法:RegisterTypes和CreateShell。
RegisterTypes
此函数用于注册所有的应用程序依赖项。例如您可能有一个接口可以从某种持久存储中读取客户数据,而它的实现是使用某种数据库。它可能看起来像这样:
public interface ICustomerStore
{
List<string> GetAll();
}
public class DbCustomerStore : ICustomerStore
{
public List<string> GetAll()
{
// return list from db
}
}
应用程序中依赖于客户数据的对象(例如视图模型)将需要一个ICustomerStore
对象。在App.RegisterTypes
函数中,每当对象依赖于ICustomerStore
时,都会进行注册以创建DbCustomerStore
。
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<Services.ICustomerStore, Services.DbCustomerStore>();
// register other needed services here
}
IContainerRegistry还有其他可以用于注册接口的函数。比如
RegisterInstance
将针对接口注册已创建的对象实例,其中注册接口的实现实际上是单例的。一个类似的方法是RegisterSingleton
,它将在建立依赖关系时而不是之前便创建一个实例。值得注意的是,Container
也可以在没有事先注册的情况下解析具体类型。
CreateShell
第二个要实现的方法是CreateShell方法。这个方法将创建应用程序的主窗口。其中App类的Container属性应该用来创建窗口,因为它会处理所有的依赖项。
public partial class App : PrismApplication
{
// RegisterTypes function is here
protected override Window CreateShell()
{
var w = Container.Resolve<MainWindow>();
return w;
}
}
此时,应用程序可以构建并运行,应该如下所示:
现在这已经是一个Prism应用程序了,虽然目前还没有太多的内容,但Prism可以提供很多帮助,例如将应用程序分解为可管理的块、导航和实现MVVM模式。
视图模型
WPF为使用MVVM模式进行了很好的配置,Prism在这方面也会有很大帮助。Prism有一个基类,用于处理INotifyPropertyChanged基础结构,该基础结构会将视图模型中的更改发布到视图中。此外还有一些其他类可以使从视图模型中处理按钮变得更简单,而不是在代码中编写事件处理程序。
首先需要向视图中添加一些控件,跳转到MainWindow.xaml
并添加以下<Grid>
标记作为<MainWindow>
的内容。
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"
/>
<Button
Grid.Row="1" Width="80" Height="40"
Command="{Binding CommandLoad}"
Content="LOAD"
/>
</Grid>
上面将添加一个新的列表视图,它将显示客户名称列表和一个加载列表的按钮。
要记住的重要一点是,每次有一个
Binding
时,都会有一个到该视图所关联的视图模型上的链接。
为了帮助您完成入门指南的这一部分,还需要在项目中设置上面所显示内容的服务。在项目的根目录中创建一个Services
文件夹,并在该文件夹中创建CustomerStore.cs
文件并添加以下代码:
public interface ICustomerStore
{
List<string> GetAll();
}
public class DbCustomerStore : ICustomerStore
{
public List<string> GetAll()
{
return new List<string>()
{
"cust 1",
"cust 2",
"cust 3",
};
}
}
在App.xaml.cs
文件中,确保RegisterTypes
包含以下内容:
containerRegistry.Register<Services.ICustomerStore, Services.DbCustomerStore>();
创建视图模型
首先,在项目的根目录下创建一个名为ViewModels
的文件夹。请您务必使用该准确名称,因为稍后在讨论视图模型解析时会需要它。
在ViewModels
文件夹中,创建了一个名为MainWindowViewModel
的类,其中使用这个准确名字的原因将在后面展示。Prism有一个名为BindableBase
的类,它被用作所有视图模型的基础,MainWindowViewModel
也将继承于它。
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp1.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private Services.ICustomerStore _customerStore = null;
public MainWindowViewModel(Services.ICustomerStore customerStore)
{
_customerStore = customerStore;
}
public ObservableCollection<string> Customers { get; private set; } =
new ObservableCollection<string>();
private string _selectedCustomer = null;
public string SelectedCustomer
{
get => _selectedCustomer;
set
{
if (SetProperty<string>(ref _selectedCustomer, value))
{
Debug.WriteLine(_selectedCustomer ?? "no customer selected");
}
}
}
private DelegateCommand _commandLoad = null;
public DelegateCommand CommandLoad =>
_commandLoad ?? (_commandLoad = new DelegateCommand(CommandLoadExecute));
private void CommandLoadExecute()
{
Customers.Clear();
List<string> list = _customerStore.GetAll();
foreach (string item in list)
Customers.Add(item);
}
}
}
解释一下这里发生了什么。MainWindowViewModel依赖于ICustomerStore
接口,因此该接口必须在App.RegisterTypes
中注册,以便其实现可以由依赖容器处理。其中有一个Customers
属性绑定到用户界面中的ListView上,还有一个SelectedCustomer
绑定到ListView中的当前选择项上。
还有一个实现ICommand
接口的CommandLoad对象,它有一个Execute
方法,会在每当用户点击按钮时调用。Prism使用了DelegateCommand
类实现了ICommand
接口,它允许传递委托来处理实现ICommand
接口。在CommandLoad
这种情况中,CommandLoadExecute
函数会作为委托传入,于是现在每当WPF绑定系统尝试执行ICommand.Execute
时,CommandLoadExecute
都会被调用。
有关DelegateCommand的更多详细信息,请参阅 命令。
使用ViewModelLocator
现在有一个视图和一个视图模型,但它们是如何链接在一起的?该功能开箱即用,因为Prism有一个ViewModelLocator
,它使用约定来确定视图模型的正确类,用其依赖关系实例化它,并将其附加到视图的DataContext
。
默认约定是将所有视图放在Views
文件夹中,将视图模型放在ViewModels
文件夹中。
WpfApp1.Views.MainWindow
=>WpfApp1.ViewModels.MainWindowViewModel
WpfApp1.Views.OtherView
=>WpfApp1.ViewModels.OtherViewModel
这是可配置的,并且可以添加不同的解析逻辑。
为此,视图和视图模型必须正确地位于其正确的名称空间中。下面是它的屏幕截图:
单击此处了解有关ViewModelLocator
的详细信息。
如果你出于某些原因不想使用此功能,则必须在视图中选择关闭。您可以按如下方式在XAML中管理此项:
<Window
...
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="False"
>
<!-- ui controls here -->
</Window>