(一)Prism的区域
引用上篇的代码
ViewModel这段代码虽然能完成功能,但是有下面的缺点:
1。 viewmodel里加入太多的控制代码,你Ui如果复杂点,会变成到处都是binding,造成viewmodel中的代码维护越来越复杂。
2。Open中那个丑陋的switch,让人想到为啥它不是依赖注入呢?
public class MainWindowViewModel : BindableBase { public DelegateCommand<string> OpenCommand { get;private set; } private string _title = "Prism Application33"; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private object body; public object Body { get { return body; } set { //body= value; //RaisePropertyChanged(); SetProperty(ref body, value); } } public MainWindowViewModel() { OpenCommand = new DelegateCommand<string>(Open); } private void Open(string obj) { switch(obj) { case "ViewA": Body = new ViewA(); break; case "ViewB": Body = new ViewB(); break; case "ViewC": Body = new ViewC(); break; } } }
可以使用Prism的区域功能来简化上面的过程:
(一)MainWindowViewModel的变化
我们取消了原来的Body,采用依赖注入的方式,用构造函数的DI方式注入IRegionManager
在app.xmal.cs代码中,我们会往容器内添加三个View:ViewA,ViewB,ViewC
我们看到现在的代码就不再需要费力的去用代码维护view的binding。
而且更重要的是,在后面的例子里,ViewA这样的View可以是另一个项目的,也就是说可以跨项目模块化调用。
private readonly IRegionManager regionManager; public MainWindowViewModel(IRegionManager region) { OpenCommand = new DelegateCommand<string>(Open); this.regionManager = region; } private void Open(string obj) { //首先通过IRegionManager接口获取全局定义的可用区域 //往这个区域动态的去设置内容,方式是使用依赖注入 this.regionManager.Regions["ContentRegion"].RequestNavigate(obj); }
(二)app.xmal.cs代码的变化
往容器内添加三个View:ViewA,ViewB,ViewC
protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewA>(); containerRegistry.RegisterForNavigation<ViewB>(); containerRegistry.RegisterForNavigation<ViewC>(); }
(三)MainWindow.xmal的变化
在view中定义一个区域,并命名为ContentRegion。
在第(一)步的Open函数中,会用到这个区域的命名。
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion"/>
源代码:
链接:https://pan.baidu.com/s/1ldo23MdBBs8zLJNTz-MmWg
提取码:e98u
--来自百度网盘超级会员V6勇哥的分享
(二)Prism的模块化
把ViewA,B,C放到独立的项目里去,利用override方法ConfigureModuleCatalog添加三个模块。
有两种方式,一是要引用三个模块的命名空间,二是不用引用,直接动态读取指定目录下的模块。
现在介绍第一种方法:
创建三个wpf类库项目
引用Prism.DryIoc。
创建View目录,创建wpf用户控件ViewA,在其xaml里放入TextBlock,这个跟之前一样。
唯一不同的是,我们要创建一个类,名称任意,它用来标识这是一个模块。
这个类的内容如下:
就是要继承IModule,我们只用实现它的RegisterTypes
using Prism.Ioc; using Prism.Modularity; namespace ModuleA.View { public class ModuleAProfile : IModule { public void OnInitialized(IContainerProvider containerProvider) { //throw new NotImplementedException(); } public void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.RegisterForNavigation<ViewA>(); } } }
MainWindowViewModel不做任何变化。
App.xaml.cs变化如下:
去掉之前在RegisterTypes里写的依赖注入的容器内容
ConfigureModuleCatalog方法里添加三个模块的标识模块的类
using FullApp1.Modules.ModuleName; using FullApp1.Services; using FullApp1.Services.Interfaces; using FullApp1.Views; using ModuleA.View; using ModuleB.View; using ModuleC.View; using Prism.Ioc; using Prism.Modularity; using System.Windows; namespace FullApp1 { /// <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) { } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { moduleCatalog.AddModule<ModuleAProfile>(); moduleCatalog.AddModule<ModuleBProfile>(); moduleCatalog.AddModule<ModuleCProfile>(); } } }
源代码:
链接:https://pan.baidu.com/s/1gBTWSV6c0xFUovCMsgt8jw
提取码:k974
--来自百度网盘超级会员V6勇哥的分享
第二种方法:
App.xaml.cs变化如下:
设置模块目录为当前exe的目录下的Modules下。
protected override IModuleCatalog CreateModuleCatalog() { return new DirectoryModuleCatalog() { ModulePath = @".\Modules" }; }
其它代码不用变化。
为了方便把三个模块的dll都输出到这个目录,可以设置编译完成后的事件:
copy "$(ProjectDir)bin\Debug\net6.0-windows7.0\$(ProjectName).dll" "$(SolutionDir)FullApp1\bin\Debug\net6.0-windows\Modules\$(ProjectName).dll"
如果这个路径有问题,可以查看vs输出窗口显示的错误路径串,改正后即可。
第二种方式不需要程序强引用三个模块的命名空间。它和三个模块之间是完全没有耦合。
源码下载:
链接:https://pan.baidu.com/s/1GrFPyF90uhbZ5SfeVsalFA
提取码:pikt
--来自百度网盘超级会员V6勇哥的分享
prism还提供配置文件载入模块,xml方式载入等。
详细请参考github上的示例代码:https://github.com/PrismLibrary/Prism-Samples-Wpf

