WPF Prism学习实例理解总结 MEF
MEF:(在分模块建立DLL时不能建立C#的类库,要建立WPF的用户控件库或自定义控件库)
1.创建了一个catalog,它将告诉MEF到什么地方去寻找Import和Export。在这个例子中,我们告知在当前运行的程序集中。出此之外还有很多种catalog,我们稍候会看到,当然你也可以去创建自己的catalog。
2.创建了一个CompositionContainer,这是个高效的方式使不同的part在一起被调用。
3.将Program的实例加入到container以便调用其依赖项。
4.施展Compose魔法!Message属性将在这步得到设置。就相当于设置应用到某个类。
导出就相当于创建了一个实例。
而导入则是从一个容器中的组合部件中去查找并赋值。
而对于容器的组合部件方式主要有如下几种:
AssemblyCatalog 用于分析存在于指定程序集中的所有部分。 可以通过对象引用或通过路径指定目标程序集。类型是线程安全的。从托管代码程序集创建的不可变的 ComposablePartCatalog 对象。
DirectoryCatalog 分析指定目录的内容。 将提取 DLL 文件中包含的任何特性化部分,并通过目录提供。此外,还可以使用与 GetFiles 相同的语法指定一个搜索模式,以将分析限制到特定 DLL。 一个表示目录的内容的 ComposablePartCatalog 对象。
AggregateCatalog 包含 ComposablePartCatalog 对象的可变集合的目录。
var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new DirectoryCatalog("."));//加载DLL _container = new CompositionContainer(catalog); try { _container.ComposeParts(this); //组合本程序集 } catch (CompositionException compositionException) { MessageBox.Show(compositionException.ToString()); return false; }
2.
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); //将部件(part)和宿主程序添加到组合容器 container.ComposeParts(this,new ComputerBookService()); //扩展方法带This调用
3.
var catalog = newAttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()); var container = newCompositionContainer(catalog.CreateResolver()); container.AddPart(this); container.Compose();//该函数是在容器中添加或移除指定的 CompositionBatch 中的部件并执行组合。
4.1 加载分析程序集的方式
var catelog = newDirectoryPartCatalog(@"..\..\..\HelloWorldMessage\bin\Debug");//从目录中加载DLL // new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()); var container = newCompositionContainer(catelog.CreateResolver()); container.AddPart(this); container.Compose();
4.2
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(QuickStartBootstrapper).Assembly));
//将相关的程序集都加入到 这个是从AppConfig中 // Module A is referenced in in the project and directly in code. this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ModuleA).Assembly));//这个是从引用程序集[DLL]中 this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ModuleC).Assembly)); // Module B and Module D are copied to a directory as part of a post-build step. // These modules are not referenced in the project and are discovered by inspecting a directory. // Both projects have a post-build step to copy themselves into that directory. DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules");//这个是从目录[DLL]文件中 this.AggregateCatalog.Catalogs.Add(catalog);
5。自己
var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly())); var catalogDic = new DirectoryCatalog(@"DirectoryModules"); catalog.Catalogs.Add(catalogDic); container = new CompositionContainer(catalog); //将部件(part)和宿主程序添加到组合容器 container.ComposeParts(this);
PRISM:
App调用Bootstrapper的Run,
Booststrapper会New一个新的Shell,
public partial class Shell : Window { public Shell( IShellViewModel viewModel ) { InitializeComponent(); ViewModel = viewModel; } public IShellViewModel ViewModel { get { return ( IShellViewModel )DataContext; } private set { DataContext = value; } } private void TreeView_Loaded( object sender, RoutedEventArgs e ) { TreeView tv = ( TreeView )sender; tv.Items.SortDescriptions.Add( new SortDescription( "Header", ListSortDirection.Ascending ) ); } }
Shell继承自Window.而且只接把ViewModel做为DataContext与Shell绑定起来。
<modules> <module assemblyFile="Samples.Modules.BusyIndicator.dll" moduleType="Samples.Modules.BusyIndicator.BusyIndicatorModule, Samples.Modules.BusyIndicator" moduleName="BusyIndicatorModule" /> <module assemblyFile="Samples.Modules.Button.dll" moduleType="Samples.Modules.Button.ButtonModule, Samples.Modules.Button" moduleName="ButtonModule" /> <module assemblyFile="Samples.Modules.Calculator.dll" moduleType="Samples.Modules.Calculator.CalculatorModule, Samples.Modules.Calculator" moduleName="CalculatorModule" /> <module assemblyFile="Samples.Modules.CheckLists.dll" moduleType="Samples.Modules.CheckLists.CheckListsModule, Samples.Modules.CheckLists" moduleName="CheckListsModule" /> <module assemblyFile="Samples.Modules.ChildWindow.dll" moduleType="Samples.Modules.ChildWindow.ChildWindowModule, Samples.Modules.ChildWindow" moduleName="ChildWindowModule" /> <module assemblyFile="Samples.Modules.DataGrid.dll" moduleType="Samples.Modules.DataGrid.DataGridModule, Samples.Modules.DataGrid" moduleName="DataGridModule" /> <module assemblyFile="Samples.Modules.Color.dll" moduleType="Samples.Modules.Color.ColorModule, Samples.Modules.Color" moduleName="ColorModule" /> <module assemblyFile="Samples.Modules.DateTime.dll" moduleType="Samples.Modules.DateTime.DateTimeModule, Samples.Modules.DateTime" moduleName="DateTimeModule" /> <module assemblyFile="Samples.Modules.Magnifier.dll" moduleType="Samples.Modules.Magnifier.MagnifierModule, Samples.Modules.Magnifier" moduleName="MagnifierModule" /> <module assemblyFile="Samples.Modules.Numeric.dll" moduleType="Samples.Modules.Numeric.NumericModule, Samples.Modules.Numeric" moduleName="NumericModule" /> <module assemblyFile="Samples.Modules.MessageBox.dll" moduleType="Samples.Modules.MessageBox.MessageBoxModule, Samples.Modules.MessageBox" moduleName="MessageBoxModule" /> <module assemblyFile="Samples.Modules.Pie.dll" moduleType="Samples.Modules.Pie.PieModule, Samples.Modules.Pie" moduleName="PieModule" /> <module assemblyFile="Samples.Modules.PropertyGrid.dll" moduleType="Samples.Modules.PropertyGrid.PropertyGridModule, Samples.Modules.PropertyGrid" moduleName="PropertyGridModule" /> <module assemblyFile="Samples.Modules.Text.dll" moduleType="Samples.Modules.Text.TextModule, Samples.Modules.Text" moduleName="TextModule" /> <module assemblyFile="Samples.Modules.TimelinePanel.dll" moduleType="Samples.Modules.TimelinePanel.TimelinePanelModule, Samples.Modules.TimelinePanel" moduleName="TimelinePanelModule" /> <module assemblyFile="Samples.Modules.Wizard.dll" moduleType="Samples.Modules.Wizard.WizardModule, Samples.Modules.Wizard" moduleName="WizardModule" /> <module assemblyFile="Samples.Modules.Zoombox.dll" moduleType="Samples.Modules.Zoombox.ZoomboxModule, Samples.Modules.Zoombox" moduleName="ZoomboxModule" /> </modules>
App.config用配置文件的方法加载各个模块到ConfigurationModuleCatalog中。
<TreeView prism:RegionManager.RegionName="{x:Static inf:RegionNames.NavigationRegion}" infCommands:TreeViewSelected.Command="{Binding NavigateCommand}" BorderBrush="{x:Null}" MinWidth="225" Margin="3" Loaded="TreeView_Loaded"> <TreeView.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#A1000000" Offset="0" /> <GradientStop Color="Black" Offset="1" /> </LinearGradientBrush> </TreeView.Background> </TreeView>
TreeViewSelect:修改TreeView的SelectItemChanged事件,通过设置附加属性Command,进而设置SelectCommandBehivorProperty属性(附加属性相当于附加对象的属性),可以用GetValue,SetValue进行变更。
DelegateCommand只提供CanExcute, Excute;
CommandBehaviorBase中要提供一个Command及关联的Control(TargetObject),还要提供一个CommandParameter,派生类即可将控件的Click事件等转成执行Command.
public ShellViewModel( IRegionManager regionManager ) { _regionManager = regionManager; NavigateCommand = new DelegateCommand<string>( Navigate ); } private void Navigate( string navigatePath ) { if( !String.IsNullOrWhiteSpace( navigatePath ) ) _regionManager.RequestNavigate( RegionNames.ContentRegion, navigatePath ); }
void SelectedItemChanged( object sender, RoutedPropertyChangedEventArgs<object> e ) { //This treeview command is specfic to the navigation region, //so I always want to pass the tag of the selected treeviewitem //because it will conatin the Type of view to navigate to. var type = ( e.NewValue as FrameworkElement ).Tag as Type; CommandParameter = type != null ? type.FullName : null; ExecuteCommand(); }
通过将事件转换在SelectedItemChanged的时候将会调用Navigate并将上面的type.FullName传递给其参数,从而达到ContentRegion切换页面的目的。
在模块中:
Module中只有一个初始化函数
public void Initialize() { //types must be registered first RegisterViewsAndTypes(); //now initialize the module InitializeModule(); }
protected override void RegisterViewsAndTypes() { Container.RegisterNavigationType( typeof( BusyIndicatorView ) ); Container.RegisterNavigationType( typeof( BusyIndicatorCustomContentView ) ); Container.RegisterNavigationType( typeof( BusyIndicatorCustomContentTemplateView ) ); }
public static void RegisterNavigationType( this IUnityContainer container, Type type ) { container.RegisterType( typeof( Object ), type, type.FullName ); }
Model类中的Container的RegisterNavigationType是扩展方法,使用RegisterType向Container提供视图名称,将视图名称与视图类型进行关联,这里取了类型的全名。在进行导航显示时只需要使用视图名称就可以找到视图。
protected override void InitializeModule() { RegionManager.RegisterViewWithRegion( RegionNames.NavigationRegion, typeof( BusyIndicatorNavItem ) ); }
RegionManager.RegisterViewWithRegion( RegionNames.NavigationRegion, typeof( BusyIndicatorNavItem ) );将对应的区域性视图与相应的区域进行关联, 像TreeView为容器时就必须用继承于TreeItem的类。
<TreeViewItem x:Class="Samples.Modules.Button.NavigationItems.ButtonSpinnerNavItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:navItems="clr-namespace:Samples.Modules.Button.NavigationItems" xmlns:views="clr-namespace:Samples.Modules.Button.Views" Header="ButtonSpinner" Tag="{x:Type views:ButtonSpinnerView}" > <TreeViewItem.Resources> <Style TargetType="navItems:ButtonSpinnerNavItem" BasedOn="{StaticResource {x:Type TreeViewItem}}" /> </TreeViewItem.Resources> </TreeViewItem>
而BusyIndicatorNavItem 区域性视图中的每个Item的Tag与 一个View相关联,(即一个Item选项对应 一个View视图),当选中时会将类型传递到会发生SelectItemChanged事件,之后会调用Navigate……(参考上面)。

浙公网安备 33010602011771号