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……(参考上面)。

 

posted @ 2014-08-14 10:50  高_山_流_水  阅读(494)  评论(0)    收藏  举报