04Prism WPF 入门实战 - Module

1.概要

源码及PPT地址:https://github.com/JusterZhu/wemail

视频地址:https://www.bilibili.com/video/BV1KQ4y1C7tg?sharesource=copyweb

Module,具有特定功能,且独立存在则称为成为模块。下图为Prism体系中的关系结构图。

522581e77a56b4428ab0ee19cf57cce4.png

在Prism体系中Module的应用分为

  • 注册/发现模块

  • 加载模块

  • 初始化模块

a9d377c2a56691478f10d15538336d1f.png

2.详细内容

  • (1)注册/发现模块

通过重写CreateModuleCatalog方法指定加载module的方式,这里我个人比较推荐使用反射的方式去指定目录下读取,当然还有其他方式这里就不一 一介绍了。

首先我们将项目中的module编译生成到项目运行目录下的Apps文件夹下。

1b1fceaa5e67be011fa379c74aeb97e7.png

这时需要在类库右键->点击属性。

9c57f60f06200455b17797c981c794e5.png

将DLL编译生成时拷贝到,指定目录下(详情见源码)。

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{/// <summary>/// 应用程序启动时创建Shell/// </summary>/// <returns></returns>protected override Window CreateShell(){return Container.Resolve<MainWindow>();}protected override void RegisterTypes(IContainerRegistry containerRegistry){//注册服务、依赖、View}/// <summary>/// 配置区域适配/// </summary>/// <param name="regionAdapterMappings"></param>protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings){base.ConfigureRegionAdapterMappings(regionAdapterMappings);}protected override IModuleCatalog CreateModuleCatalog(){//new ConfigurationModuleCatalog()//指定模块加载方式为从文件夹中以反射发现并加载module(推荐用法)return new DirectoryModuleCatalog() { ModulePath = @".\Apps" };}
}
  • (2)加载模块

加载模块的代码实现在DirectoryModuleCatalog内部实现大致如下:

//
// Summary:
//     Represets a catalog created from a directory on disk.
//
// Remarks:
//     The directory catalog will scan the contents of a directory, locating classes
//     that implement Prism.Modularity.IModule and add them to the catalog based on
//     contents in their associated Prism.Modularity.ModuleAttribute. Assemblies are
//     loaded into a new application domain with ReflectionOnlyLoad. The application
//     domain is destroyed once the assemblies have been discovered. The diretory catalog
//     does not continue to monitor the directory after it has created the initialze
//     catalog.
public class DirectoryModuleCatalog : ModuleCatalog
{private class InnerModuleInfoLoader : MarshalByRefObject{internal ModuleInfo[] GetModuleInfos(string path){DirectoryInfo directory = new DirectoryInfo(path);ResolveEventHandler value = (object sender, ResolveEventArgs args) => OnReflectionOnlyResolve(args, directory);AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += value;ModuleInfo[] result = GetNotAlreadyLoadedModuleInfos(IModuleType: AppDomain.CurrentDomain.GetAssemblies().First((Assembly asm) => asm.FullName == typeof(IModule).Assembly.FullName).GetType(typeof(IModule).FullName), directory: directory).ToArray();AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= value;return result;}private static IEnumerable<ModuleInfo> GetNotAlreadyLoadedModuleInfos(DirectoryInfo directory, Type IModuleType){List<Assembly> list = new List<Assembly>();Assembly[] alreadyLoadedAssemblies = (from p in AppDomain.CurrentDomain.GetAssemblies()where !p.IsDynamicselect p).ToArray();foreach (FileInfo item in (from file in directory.GetFiles("*.dll")where alreadyLoadedAssemblies.FirstOrDefault((Assembly assembly) => string.Compare(Path.GetFileName(assembly.Location), file.Name, StringComparison.OrdinalIgnoreCase) == 0) == nullselect file).ToList()){try{list.Add(Assembly.LoadFrom(item.FullName));}catch (BadImageFormatException){}}return list.SelectMany((Assembly assembly) => from t in assembly.GetExportedTypes().Where(new Func<Type, bool>(IModuleType.IsAssignableFrom))where t != IModuleTypewhere !t.IsAbstractselect t into typeselect CreateModuleInfo(type));}private static Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory){Assembly assembly = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies().FirstOrDefault((Assembly asm) => string.Equals(asm.FullName, args.Name, StringComparison.OrdinalIgnoreCase));if (assembly != null){return assembly;}AssemblyName assemblyName = new AssemblyName(args.Name);string text = Path.Combine(directory.FullName, assemblyName.Name + ".dll");if (File.Exists(text)){return Assembly.ReflectionOnlyLoadFrom(text);}return Assembly.ReflectionOnlyLoad(args.Name);}internal void LoadAssemblies(IEnumerable<string> assemblies){foreach (string assembly in assemblies){try{Assembly.ReflectionOnlyLoadFrom(assembly);}catch (FileNotFoundException){}}}private static ModuleInfo CreateModuleInfo(Type type){string name = type.Name;List<string> list = new List<string>();bool flag = false;CustomAttributeData customAttributeData = CustomAttributeData.GetCustomAttributes(type).FirstOrDefault((CustomAttributeData cad) => cad.Constructor.DeclaringType!.FullName == typeof(ModuleAttribute).FullName);if (customAttributeData != null){foreach (CustomAttributeNamedArgument namedArgument in customAttributeData.NamedArguments){switch (namedArgument.MemberInfo.Name){case "ModuleName":name = (string)namedArgument.TypedValue.Value;break;case "OnDemand":flag = (bool)namedArgument.TypedValue.Value;break;case "StartupLoaded":flag = !(bool)namedArgument.TypedValue.Value;break;}}}foreach (CustomAttributeData item in from cad in CustomAttributeData.GetCustomAttributes(type)where cad.Constructor.DeclaringType!.FullName == typeof(ModuleDependencyAttribute).FullNameselect cad){list.Add((string)item.ConstructorArguments[0].Value);}ModuleInfo obj = new ModuleInfo(name, type.AssemblyQualifiedName){InitializationMode = (flag ? InitializationMode.OnDemand : InitializationMode.WhenAvailable),Ref = type.Assembly.EscapedCodeBase};obj.DependsOn.AddRange(list);return obj;}}//// Summary://     Directory containing modules to search for.public string ModulePath{get;set;}//// Summary://     Drives the main logic of building the child domain and searching for the assemblies.protected override void InnerLoad(){if (string.IsNullOrEmpty(ModulePath)){throw new InvalidOperationException(Prism.Properties.Resources.ModulePathCannotBeNullOrEmpty);}if (!Directory.Exists(ModulePath)){throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Prism.Properties.Resources.DirectoryNotFound, ModulePath));}AppDomain currentDomain = AppDomain.CurrentDomain;try{List<string> list = new List<string>();IEnumerable<string> collection = from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()where !(assembly is AssemblyBuilder) && assembly.GetType().FullName != "System.Reflection.Emit.InternalAssemblyBuilder" && !string.IsNullOrEmpty(assembly.Location)select assembly.Location;list.AddRange(collection);Type typeFromHandle = typeof(InnerModuleInfoLoader);if (typeFromHandle.Assembly != null){InnerModuleInfoLoader innerModuleInfoLoader = (InnerModuleInfoLoader)currentDomain.CreateInstanceFrom(typeFromHandle.Assembly.Location, typeFromHandle.FullName)!.Unwrap();base.Items.AddRange(innerModuleInfoLoader.GetModuleInfos(ModulePath));}}catch (Exception innerException){throw new Exception("There was an error loading assemblies.", innerException);}}
}
  • (3)初始化模块

这些代码在使用Prism项目模板创建Module的时候就已经自动创建好了。

70f24abf400466e6528ab072d3b7696b.png

[Module(ModuleName = "Contact")]
public class ContactModule : IModule
{//初始化public void OnInitialized(IContainerProvider containerProvider){//通过注册RegionManager,添加ContactViewvar regionManager = containerProvider.Resolve<IRegionManager>();//通过ContentRegion管理导航默认初始页面ContactViewvar contentRegion = regionManager.Regions["ContentRegion"];contentRegion.RequestNavigate(nameof(ContactView));}public void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterForNavigation<ContactView>();}
}

3.实战应用

c58a585bf9ca113eeeff5c09fd8aa5a9.png

2371e06ed9ddb825e684fd04bd4d5330.png

Shell - MainWindow实现

<Window.Resources><Style x:Key="ModuleItemSytle" TargetType="ListBoxItem"><Setter Property="Template"><Setter.Value><ControlTemplate><Grid><TextBlock Text="{Binding ModuleName}"></TextBlock></Grid></ControlTemplate></Setter.Value></Setter></Style>
</Window.Resources>
<Grid><Grid.ColumnDefinitions><ColumnDefinition Width="2*"/><ColumnDefinition Width="8*"/></Grid.ColumnDefinitions><ListBox ItemsSource="{Binding Modules}" SelectedItem="{Binding ModuleInfo}" ItemContainerStyle="{StaticResource ModuleItemSytle}"  /><ContentControl Grid.Column="1" prism:RegionManager.RegionName="ContentRegion"/>
</Grid>
</Window>

MainWindowViewModel中的实现

public class MainWindowViewModel : BindableBase
{private string _title = "Prism Application";//Region管理对象private IRegionManager _regionManager;private IModuleCatalog _moduleCatalog;private ObservableCollection<IModuleInfo> _modules;private DelegateCommand _loadModules;private IModuleInfo _moduleInfo;public IView View { get; set; }public string Title{get { return _title; }set { SetProperty(ref _title, value); }}public ObservableCollection<IModuleInfo> Modules{get => _modules ?? (_modules = new ObservableCollection<IModuleInfo>());}public DelegateCommand LoadModules { get => _loadModules = new DelegateCommand(InitModules); }public IModuleInfo ModuleInfo { get {return _moduleInfo; }set {_moduleInfo = value;Navigate(value);}}public MainWindowViewModel(IRegionManager regionManager, IModuleCatalog moduleCatalog){_regionManager = regionManager;_moduleCatalog = moduleCatalog;}public void InitModules() {var dirModuleCatalog = _moduleCatalog as DirectoryModuleCatalog;Modules.AddRange(dirModuleCatalog.Modules);}private void Navigate(IModuleInfo info) {_regionManager.RequestNavigate("ContentRegion", $"{ info.ModuleName }View");}
}

Module - Wemail.Contact实现

ContactModule.cs 模块标记文件

[Module(ModuleName = "Contact")]
public class ContactModule : IModule
{public void OnInitialized(IContainerProvider containerProvider){//通过注册RegionManager,添加ContactViewvar regionManager = containerProvider.Resolve<IRegionManager>();//通过ContentRegion管理导航默认初始页面ContactViewvar contentRegion = regionManager.Regions["ContentRegion"];contentRegion.RequestNavigate(nameof(ContactView));}public void RegisterTypes(IContainerRegistry containerRegistry){containerRegistry.RegisterForNavigation<ContactView>();}
}

ContactView实现

<Grid><Grid.ColumnDefinitions><ColumnDefinition Width="2*"/><ColumnDefinition Width="8*"/></Grid.ColumnDefinitions><ListBox x:Name="LsbContact" ItemsSource="{Binding Contacts}"/><ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="40" Grid.Column="1" Content="{Binding ElementName=LsbContact,Path=SelectedItem}"></ContentControl>
</Grid>

ContactViewModel实现

public class ContactViewModel : BindableBase
{private ObservableCollection<string> _contacts;private string _message;public string Message{get { return _message; }set { SetProperty(ref _message, value); }}public ObservableCollection<string> Contacts { get => _contacts ?? (_contacts = new ObservableCollection<string>()); }public ContactViewModel(){Message = "Wemail.Contact Prism Module";Contacts.Add("联系人张某");Contacts.Add("联系人王某");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机(VMware Workstation)中,把连接网络的模式由“NAT模式”,改成“自动桥接模式”,网速大大的提升...

安装虚拟机&#xff0c;默认情况下&#xff0c;联网的模式是NAT&#xff0c;即跟主机是转发共用网络资源的&#xff0c;这样就非常慢&#xff0c;时常网页都打不开&#xff0c;现把它改成桥接模式&#xff0c;让它独立成为一台物理机&#xff0c;网速有大大的改善&#xff0c;设…

如何保持纯洁男女关系……

1 倒也没毛病▼2 差点以为是狗子&#xff01;&#xff01;▼3 大哥&#xff1a;我裤子没破&#xff01;▼4 女朋友梦到了啥&#xff1f;&#xff1f;▼5 忍不住了&#xff0c;嘻嘻嘻...&#xff08;via.小风车车&#xff09;▼6 亲爸爸&#xff01;&#xff01;▼7 哈哈哈…

【转】一个关于fork()的笔试题,考了好几遍,终于找到答案了

笔试至少3次见到这个题&#xff0c;都是瞎编的&#xff0c;今天群里有人问&#xff0c;然后有人放出了这个地址&#xff1a;http://coolshell.cn/articles/7965.html&#xff0c;让我恍然大明白&#xff0c;豁然好脾气。 感谢这位陈皓同学&#xff08;名字很熟&#xff0c;不记…

C# 选中 DataGridView 控件中的行时显示不同的颜色

可以利用 DataGridView 控件的 SelectionMode、ReadOnly 和 SelectionBackColor 属性实现当选中DataGridView控件中的行时显示不同的颜色。SelectionMode属性用于设置如何选择 DataGridView 的单元格。语法如下:public DataGridViewSelectionMode SelectionMode{get;set;}属性值…

32岁武汉硕士毕业4年后重新高考,考上本硕需再读8年:“不是一时冲动”

全世界只有3.14 % 的人关注了爆炸吧知识9月5日&#xff0c;程传坤收到了湖北中医药大学的录取通知书。7月8日下午5时10分&#xff0c;32岁的程传坤走出湖北省武汉市新洲一中考点&#xff0c;一脸轻松&#xff0c;拿着准考证特意在新洲一中门前留影。这是他硕士毕业4年后再战高考…

打开本地文件_可以跨软件搜索文件?结构式检索你一定要学会!

面对电脑中日积月累的大量结构式&#xff0c;如何能快速找到自己想要的文件&#xff0c;有时真是一个让人头疼的问题。KingDraw PC版内置的结构式检索功能&#xff0c;可以帮助我们轻松解决这个难题。KingDraw PC版中&#xff0c;我们有两种途径可以检索结构式——右键菜单中检…

WPF实现雷达图(仿英雄联盟)

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织转载 有小伙伴提出需要实现雷达图。 由于在WPF中没有现成的雷达图控件&#xff0c;所以我们自己实现一个。PS&#xff1a;有更好的方式欢迎推荐。01—代码如…

python3 2.00gb怎么去掉单位_最值得期待的Python 3.9的新功能

Python 3.9 beta预计下个月就要发布了&#xff0c;那么3.9有那些让我们期待的新功能和变更呢&#xff1f;本我我们一起来说Python 3.9的新功能的。安装测试版为了能够实际探索Python 3.9 的功能&#xff0c;我们需要先下载一个Python 3.9 alpha/beta并安装。wget https://www.p…

这6部超经典的物理电影,居然还有人没有看过?

全世界只有3.14 % 的人关注了爆炸吧知识开篇警告&#xff1a;这是一篇福利文&#xff01;今天小编给热爱物理及数学的小伙伴们&#xff0c;分享6部豆瓣评分8分以上&#xff0c;与数学和物理领域相关的经典电影&#xff0c;帮助大家在工作、学习之余劳逸结合。这些影片除了涉及数…

产品说,我只需要一个有亿点复杂的查询界面

有的时候&#xff0c;你需要动态构建一个比较复杂的查询条件&#xff0c;传入数据库中进行查询。而条件本身可能来自前端请求或者配置文件。那么这个时候&#xff0c;表达式树&#xff0c;就可以帮助到你。本文我们将通过几个简短的示例来了解如何完成这些操作。你也可能接到过…

PostgreSQL忘记输入where条件update更新整张表的解决办法

2019独角兽企业重金招聘Python工程师标准>>> 虽然出现这个错误很挫&#xff0c;但有时候还是会被你或者你的同事碰到。为了避免这个错误&#xff0c;PostgreSQL数据库中可以通过触发器来解决&#xff0c;这里用的是plpgsql 。 1、修改postgresql.conf配置 增加&…

视觉开发需要什么程度的数学_角度的概念在视觉上非常直观,但其数学定义并不是那么简单...

角的概念是几何学中最基本的概念之一。当我们研究三角形的性质时&#xff0c;我们自然地建立了三角形的边和角之间的联系。这些联系是在三角学中系统地建立起来的。角是什么&#xff1f;我们如何测量它&#xff1f;虽然角度的概念在视觉上很直观&#xff0c;但它的数学定义却不…

别薅了别薅了!!!再薅就真的被薅秃了!!

▲ 点击查看大家好&#xff0c;超模全新的固定栏目「薅羊毛」上线了&#xff01;既然是薅羊毛&#xff0c;怎么能空着手来&#xff1f;毕竟好用的好吃的&#xff0c;啥都要花钱。与其为那些虚幻的包装价值买单&#xff0c;不如跟着超模君狠狠地薅一把羊毛&#xff0c;「花小钱赚…

GitHub Universe 2021|MS Reactor 邀你共聚年度盛会

关注我们GitHub Universe 2021 将于2021年10月27-28日&#xff08;PDT&#xff09;在线直播&#xff0c;MS Reactor 将与 CSDN 合作进行转播&#xff0c;与你一同观看这场全球开发者盛会。 关于 GitHub UniverseGitHub Universe 是 GitHub 面向全球开发者社区举办的年度重要盛会…

C#中的多线程 - 并行编程 z

原文&#xff1a;http://www.albahari.com/threading/part5.aspx 专题&#xff1a;C#中的多线程 1并行编程Permalink 在这一部分&#xff0c;我们讨论 Framework 4.0 加入的多线程 API&#xff0c;它们可以充分利用多核处理器。 并行 LINQ&#xff08;Parallel LINQ&#xff09…

java数组深拷贝和浅拷贝_java中的深拷贝与浅拷贝(值类型 vs 引用类型)

对象赋值赋值是日常编程过程中最常见的操作&#xff0c;最简单的比如&#xff1a;Student codeSheep new Student(); Student codePig codeSheep;严格来说&#xff0c;这种不能算是对象拷贝&#xff0c;因为拷贝的仅仅只是引用关系&#xff0c;并没有生成新的实际对象&#x…

各大厂抢招WPF,小米这回是下了血本啊...

九银十进入尾声&#xff0c;小米又爆出高薪岗位&#xff1a;35k左右&#xff0c;14薪&#xff0c;招5年左右.NET&#xff0c;要求WPF和自动化( 职位&#xff1a;https://app.mokahr.com/apply/xiaomi/287/#/job/523278c0-c504-4cdc-bb88-28c1b101ac76)。今年招WPF的大厂太多了&…

你永远都不知道你老公可以多幼稚......

1 爸爸带女儿&#xff01;两个幼稚鬼▼2 常州一小区提醒防疫四种语言切换无压力▼3 我知道了&#xff01;他的门牙肯定有条缝▼4 狗子OS&#xff1a;今天栏杆和木棍必须要断一个▼5 掀起你的假发来让我帮你擦擦汗▼6 干啥啥不行&#xff0c;吃饭第一名▼7 一看就是亲妈&…

没有女朋友,可能是因为你数学不好

全世界只有3.14 % 的人关注了爆炸吧知识孔子和耶稣曾说过&#xff1a;初恋无限好。回想起青涩的大学时光&#xff0c;告别了高中时代紧张的学习氛围和父母、老师的谆谆告诫&#xff0c;爱情也不再是伊甸园里的禁果。关于爱情的开展和维系&#xff0c;在Levinger&#xff08;198…

C#10,带来了Date和Time类型

C#10引入了日期DateOnly&#xff0c;时间TimeOnly&#xff1a;//从DateTime转换 Console.WriteLine(DateOnly.FromDateTime(DateTime.Now)); //从字会串转换 Console.WriteLine(DateOnly.Parse("2021-10-23")); //从0001-01-01到现在的天数 Console.WriteLine(DateOn…