首先记录一个错误的解决办法,在使用Prism中在新增的Module中添加
Microsoft.Practices.Prism.MefExtensions的引用时需要注意将其“复制本地”改为false,否则会报以下错误:
An exception occurred while initializing module 'Module1'.
- The exception message was: 撰写保持不变。由于以下错误,更改被拒绝: 撰写生成多个撰写错误,具有 15 个根本原因。下面提供了根本原因。 有关详细信息,请检查 CompositionException.Errors 属性
回到正题,在silverlight中最常见得开发模式是MVVM+Prism+WCF RIA,通过前面的学习已基本账务了MVVM架构,至于WCF RIA需要学习的是EF以及我们需要灵活掌握异步开发模式。下面以实例说明一个简单的MVVM+Prism的架构。
首先理下思路:
1、利用前面学习的知识建立Bootstrapper ,并建立加载Shell,在Shell中布局Region
2、在Bootstrapper中重载CreateModuleCatalog方法,确定Module加载。
3、创建Module(刚学silverlight时习惯建立silverlight类库,而类库是无法形成xap),新建module的加载类,注意在该加载类中的属性标示名称需要和我们前面定义加载的xaml配置文件的module名称一致
[ModuleExport("Module1", typeof(Module1))]
4、在新的Module中新增View,ViewModel,在View中建立与ViewModel绑定关系
5、在Module加载类的初始化接口函数中指定Module初始加载的视图到指定的Region中
6、再次以代码验证上节说介绍的有关Export,Import,这将会在View、ViewModel中应用,同时需要掌握有关于如何灵活的将View注册到对应的Region中
到此基本上可以利用Prism对模块进行动态加载,同时如果将View注入到对应的Region中,而至于MVVM与原先的模式没有太多变化,只是更多的用到了MEF注入。下面需要研究思考的是关于Module之间如果通信的问题了,可以好好考虑学习下利用IEventAggregator 来实现模块间事件的订阅与发布,似乎有点类似于MVVM中的Messager了。
在基本理清了思路后,接下来做些简单的代码说明
1、Bootstrapper类
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.MefExtensions;
using System.ComponentModel.Composition.Hosting;
namespace Prism.MVVM.Test
{
/// <summary>
/// 将MefExtensions的引用复制模式修改为false
/// 很重要
/// </summary>
public class Bootstrapper:MefBootstrapper
{
/// <summary>
/// 创建Shell,从Container中获取注入的Shell实例
/// </summary>
/// <returns></returns>
protected override DependencyObject CreateShell()
{
return this.Container.GetExportedValue<Shell>();
}
/// <summary>
/// 初始化Shell,设置启动界面为ShellView
/// </summary>
protected override void InitializeShell()
{
base.InitializeShell();
App.Current.RootVisual = (UIElement)this.Shell;
}
/// <summary>
/// 将自身添加到目录中,很重要,否则系统启动会报错
/// </summary>
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly));
}
/// <summary>
/// 可建立xaml文件配置加载模块
/// </summary>
protected override Microsoft.Practices.Prism.Modularity.IModuleCatalog CreateModuleCatalog()
{
return
Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(new Uri("/Prism.MVVM.Test;component/ModulesCatalog.xaml",
UriKind.Relative));
}
protected override CompositionContainer CreateContainer()
{
var container = base.CreateContainer();
CompositionHost.Initialize(container);
return container;
}
}
}
2、Shell布局,在该布局中主要用了ControlControl,如配合使用telerik下的RadTransitionControl 将会有更好的动画效果展现
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="#FFE2E25E">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="104*" />
<ColumnDefinition Width="296*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="62*" />
<RowDefinition Height="238*" />
</Grid.RowDefinitions>
<Border BorderBrush="Silver" BorderThickness="1" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="0" Name="border1" VerticalAlignment="Stretch" Background="#FF4848B9">
<ContentControl Name="contentControl1" prism:RegionManager.RegionName="MainTitleRegion" />
</Border>
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Stretch" Margin="0" Name="border2" VerticalAlignment="Stretch" CornerRadius="5" Background="#FF0B418F">
<ContentControl Name="contentControl3" prism:RegionManager.RegionName="MainContentRegion" />
</Border>
<Border BorderBrush="Silver" BorderThickness="1" Grid.Row="1" HorizontalAlignment="Stretch" Name="border3" VerticalAlignment="Stretch" CornerRadius="5" Background="#FF0B418F">
<ContentControl Name="contentControl2" prism:RegionManager.RegionName="MainNavRegion" />
</Border>
</Grid>
</UserControl>
3、module加载
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11 using Microsoft.Practices.Prism.Modularity;
12 using Microsoft.Practices.Prism.MefExtensions.Modularity;
13 using Microsoft.Practices.Prism.Regions;
14 using System.ComponentModel.Composition;
15 using Module1.View;
16 using Microsoft.Practices.ServiceLocation;
17
18 namespace Module1
19 {
20 [ModuleExport("Module1", typeof(Module1))]
21 public class Module1 : IModule, IPartImportsSatisfiedNotification
22 {
23 [Import]
24 public IRegionManager regionManager;
25 public void Initialize()
26 {
27 var titleview = ServiceLocator.Current.GetInstance(typeof(TitleView), "TitleView");
28 var navView = ServiceLocator.Current.GetInstance(typeof(NavView), "NavView");
29 this.regionManager.RegisterViewWithRegion(RegionNames.MainTitleRegion, () => { return ServiceLocator.Current.GetInstance(typeof(TitleView), "TitleView"); });
30 if (this.regionManager.Regions[RegionNames.MainNavRegion].GetView("NavView")==null)
31 this.regionManager.Regions[RegionNames.MainNavRegion].Add(navView);
32 this.regionManager.RequestNavigate(RegionNames.MainContentRegion, "DefaultContentView");
33 }
34
35 public void OnImportsSatisfied()
36 {
37 //throw new NotImplementedException();
38 }
39 }
40 }
4、创建View,ViewModel
2 public partial class TitleView : UserControl
3 {
4 public TitleView()
5 {
6 InitializeComponent();
7 }
8 [Import("TitleViewModel")]
9 public TitleViewModel ViewModel { get { return this.DataContext as TitleViewModel; } set { this.DataContext = value; } }
10 }
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11 using System.ComponentModel.Composition;
12
13 namespace Module1.ViewModel
14 {
15 [Export("TitleViewModel")]
16 public class TitleViewModel
17 {
18 public string ProjectName { get { return "我的测试项目"; } }
19 }
20 }
,