(一)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

