04Prism WPF 入门实战 - Module
1.概要
Module,具有特定功能,且獨立存在則稱為成為模塊。下圖為Prism體系中的關系結構圖。
在Prism體系中Module的應用分為
注冊/發現模塊
加載模塊
初始化模塊
2.詳細內容
(1)注冊/發現模塊
通過重寫CreateModuleCatalog方法指定加載module的方式,這里我個人比較推薦使用反射的方式去指定目錄下讀取,當然還有其他方式這里就不一 一介紹了。
首先我們將項目中的module編譯生成到項目運行目錄下的Apps文件夾下。
這時需要在類庫右鍵->點擊屬性。
將DLL編譯生成時拷貝到,指定目錄下(詳情見源碼)。
///
/// Interaction logic for App.xaml
///
public partial class App
{
///
/// 應用程序啟動時創建Shell
///
///
protected override Window CreateShell
{
return Container.Resolve;
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
//注冊服務、依賴、View
}
///
/// 配置區域適配
///
///
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.Modularityodule 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.
publicclassDirectoryModuleCatalog:ModuleCatalog
{
privateclassInnerModuleInfoLoader:MarshalByRefObject
{
internal ModuleInfo GetModuleInfos(string path)
{
DirectoryInfo directory=newDirectoryInfo(path);
ResolveEventHandlervalue=(objectsender, 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;
returnresult;
}
private static IEnumerable?GetNotAlreadyLoadedModuleInfos(DirectoryInfo directory, Type IModuleType)
{
List?list=newList;
Assembly alreadyLoadedAssemblies=(frompinAppDomain.CurrentDomain.GetAssemblies
where!p.IsDynamic
selectp).ToArray;
foreach(FileInfo item in (from file in directory.GetFiles("*.dll")
where alreadyLoadedAssemblies.FirstOrDefault((Assembly assembly)=>stringpare(Path.GetFileName(assembly.Location), file.Name, StringComparison.OrdinalIgnoreCase)==0)==
selectfile).ToList)
{
try
{
list.Add(Assembly.LoadFrom(item.FullName));
}
catch(BadImageFormatException)
{
}
}
returnlist.SelectMany((Assembly assembly)=>fromtinassembly.GetExportedTypes.Where(newFunc(IModuleType.IsAssignableFrom))
wheret !=IModuleType
where!t.IsAbstract
select t into type
select 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 !=)
{
returnassembly;
}
AssemblyName assemblyName=newAssemblyName(args.Name);
stringtext=Pathbine(directory.FullName, assemblyName.Name + ".dll");
if(File.Exists(text))
{
returnAssembly.ReflectionOnlyLoadFrom(text);
}
returnAssembly.ReflectionOnlyLoad(args.Name);
}
internal void LoadAssemblies(IEnumerable?assemblies)
{
foreach(stringassemblyinassemblies)
{
try
{
Assembly.ReflectionOnlyLoadFrom(assembly);
}
catch(FileNotFoundException)
{
}
}
}
private static ModuleInfo CreateModuleInfo(Type type)
{
stringname=type.Name;
List?list=newList;
boolflag=false;
CustomAttributeData customAttributeData=CustomAttributeData.GetCustomAttributes(type).FirstOrDefault((CustomAttributeData cad)=> cad.Constructor.DeclaringType!.FullName==typeof(ModuleAttribute).FullName);
if(customAttributeData !=)
{
foreach(CustomAttributeNamedArgument namedArgumentincustomAttributeData.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 iteminfromcadinCustomAttributeData.GetCustomAttributes(type)
wherecad.Constructor.DeclaringType!.FullName==typeof(ModuleDependencyAttribute).FullName
selectcad)
{
list.Add((string)item.ConstructorArguments[0].Value);
}
ModuleInfo obj=newModuleInfo(name, type.AssemblyQualifiedName)
{
InitializationMode=(flag ? InitializationMode.OnDemand : InitializationMode.WhenAvailable),
Ref=type.Assembly.EscapedCodeBase
};
obj.DependsOn.AddRange(list);
returnobj;
}
}
//
// Summary:
// Directory containing modules to search for.
publicstringModulePath
{
get;
set;
}
//
// Summary:
// Drives the main logic of building the child domain and searching for the assemblies.
protected override void InnerLoad
{
if(string.IsOrEmpty(ModulePath))
{
thrownewInvalidOperationException(Prismperties.Resources.ModulePathCannotBeOrEmpty);
}
if(!Directory.Exists(ModulePath))
{
thrownewInvalidOperationException(string.Format(CultureInfo.CurrentCulture, Prismperties.Resources.DirectoryNotFound, ModulePath));
}
AppDomain currentDomain=AppDomain.CurrentDomain;
try
{
List?list=newList;
IEnumerable?collection=fromAssembly assemblyinAppDomain.CurrentDomain.GetAssemblies
where!(assemblyisAssemblyBuilder) && assembly.GetType.FullName !="System.Reflection.Emit.InternalAssemblyBuilder" && !string.IsOrEmpty(assembly.Location)
selectassembly.Location;
list.AddRange(collection);
Type typeFromHandle=typeof(InnerModuleInfoLoader);
if(typeFromHandle.Assembly !=)
{
InnerModuleInfoLoader innerModuleInfoLoader=(InnerModuleInfoLoader)currentDomain.CreateInstanceFrom(typeFromHandle.Assembly.Location, typeFromHandle.FullName)!.Unwrap;
base.Items.AddRange(innerModuleInfoLoader.GetModuleInfos(ModulePath));
}
}
catch(Exception innerException)
{
thrownewException("There was an error loading assemblies.", innerException);
}
}
}
(3)初始化模塊
這些代碼在使用Prism項目模板創建Module的時候就已經自動創建好了。
[Module(ModuleName="Contact")]
public class ContactModule : IModule
{
//初始化
public void OnInitialized(IContainerProvider containerProvider)
{
//通過注冊RegionManager,添加ContactView
var regionManager=containerProvider.Resolve;
//通過ContentRegion管理導航默認初始頁面ContactView
var contentRegion=regionManager.Regions["ContentRegion"];
contentRegion.RequestNavigate(nameof(ContactView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation;
}
}
3.實戰應用
Shell - MainWindow實現
MainWindowViewModel中的實現
public class MainWindowViewModel : BindableBase
{
private string _title="Prism Application";
//Region管理對象
private IRegionManager _regionManager;
private IModuleCatalog _moduleCatalog;
private ObservableCollection?_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?Modules
{
get=> _modules (_modules=new ObservableCollection);
}
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,添加ContactView
var regionManager=containerProvider.Resolve;
//通過ContentRegion管理導航默認初始頁面ContactView
var contentRegion=regionManager.Regions["ContentRegion"];
contentRegion.RequestNavigate(nameof(ContactView));
}
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation;
}
}
ContactView實現
ContactViewModel實現
public class ContactViewModel : BindableBase
{
private ObservableCollection?_contacts;
private string _message;
public string Message
{
get { return _message; }
set { SetProperty(ref _message, value); }
}
public ObservableCollection?Contacts
{
get=> _contacts (_contacts=new ObservableCollection);
}
public ContactViewModel
{
Message="Wemail.Contact Prism Module";
Contacts.Add("聯系人張某");
Contacts.Add("聯系人王某");
}
}
總結
以上是生活随笔為你收集整理的04Prism WPF 入门实战 - Module的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4条实用小建议,送给初入NLP领域的你
- 下一篇: .NET 之路 | 007 详解 .NE