Prism 2.1将模块注入ViewModel

时间:2010-01-21 21:20:32

标签: c# mvvm prism

我一直在尝试将ModuleCatalog中的模块注入我的Shell的ViewModel中,但我运气不好......

我正在我的Bootstrapper中创建ModuleCatalog,我的模块从其Initializer进入屏幕没有问题。但是,我希望能够将我的模块列表绑定到一个带有DataTemplate的容器,从而允许它们从菜单中启动!

这是我的Boostrapper文件,随着时间的推移,我将添加更多模块,但就目前而言,它只包含了我设计的“ProductAModule”:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        Container.RegisterType<IProductModule>();

        base.ConfigureContainer();
    }

    protected override IModuleCatalog GetModuleCatalog()
    {
        return new ModuleCatalog()
            .AddModule(typeof(ProductAModule));
    }

    protected override DependencyObject CreateShell()
    {
        var view = Container.Resolve<ShellView>();
        var viewModel = Container.Resolve<ShellViewModel>();
        view.DataContext = viewModel;
        view.Show();

        return view;
    }
}

继续之后,这是我的Shell的ViewModel:

public class ShellViewModel : ViewModelBase
{
    public List<IProductModule> Modules { get; set; }

    public ShellViewModel(List<IProductModule> modules)
    {
        modules.Sort((a, b) => a.Name.CompareTo(b));
        Modules = modules;
    }
}

正如您所看到的,我正在尝试注入一个IProductModule列表(ProductAModule继承了它的一些属性和方法),以便它可以绑定到我的Shell的View。是否有一些非常简单的我缺少或者不能使用Unity IoC? (我已经看到它完成了StructureMap对Prism的扩展)

还有一件事......运行应用程序时,在Bootstrapper中的Container正在解析ShellViewModel时,我收到以下异常:

  

依赖项的解析失败,type =“PrismBasic.Shell.ViewModels.ShellViewModel”,name =“”。异常消息是:当前构建操作(构建密钥构建密钥[PrismBasic.Shell.ViewModels.ShellViewModel,null])失败:尝试调用构造函数PrismBasic.Shell.ViewModels.ShellViewModel(System.Collections)时无法解析参数模块.Generic.List`1 [[PrismBasic.ModuleBase.IProductModule,PrismBasic.ModuleBase,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]] modules)。 (策略类型BuildPlanStrategy,索引3)

无论如何,简单吧......看起来很困惑......

非常感谢任何帮助!

罗布

4 个答案:

答案 0 :(得分:2)

我想你可能只是这样做:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        Container.RegisterType<IProductModule>();

        base.ConfigureContainer();
    }

    private static ObservableCollection<IProductModule> _productModules = new Obser...();
    public static ObservableCollection<IProductModule> ProductModules
    { 
         get { return _productModules; } 
    }
    protected override IModuleCatalog GetModuleCatalog()
    {
        var modCatalog = new ModuleCatalog()
            .AddModule(typeof(ProductAModule));
        //TODO: add all modules to ProductModules collection

        return modCatalog;
    }

   ...
}

然后你会有一个静态属性,任何东西都可以直接绑定,或者可以从你的ViewModel中使用。


以下是如何获取已在模块目录中注册的模块名称列表。

public class MyViewModel : ViewModel
{

      public ObservableCollection<string> ModuleNames { ... }
      public MyViewModel(IModuleCatalog catalog)
      {
           ModuleNames = new ObservableCollection<string>(catalog.Modules.Select(mod => mod.ModuleName));
      }
}

这就是它。 IModuleCatalog和IModuleManager是容器中设置的唯一内容,供您根据模块进行访问。正如我所说,你不会得到任何实例数据,因为这些模块(希望)尚未创建。您只能访问类型数据。

希望这有帮助。

答案 1 :(得分:1)

我认为你误解了模块的目的。这些模块只是您希望使用的视图和服务的容器。另一方面,shell应该只包含应用程序的主要布局。

我认为您应该做的是在shell中定义一个区域,然后在该区域中注册视图(在您的情况下是按钮)。

您希望如何根据模块部署视图和服务与您正在寻找的模块化级别更相关,即,您是否希望能够独立于视图和部署而部署ModuleA的视图和服务。 ModuleB的服务等。在您的情况下,将所有内容注册到一个模块中就足够了。

花一些时间来阅读文档提供的示例,它们非常好。

您的示例抛出示例的原因是因为您的ShellViewModel依赖于List并且该类型未在Unity中注册。此外,您正在使用Unity注册IProductModule,这是没有意义的,因为无法构建接口。

答案 2 :(得分:0)

我认为我今天遇到了类似的问题,事实证明PRISM在初始化模块之前创建了shell,因此你不能将模块中的任何服务注入shell本身。

尝试创建另一个依赖于所有其他模块并实现所需功能的模块,然后将其添加到shell中的某个区域以显示您的服务列表。不幸的是,我还没有机会尝试,但这是我计划实施的解决方案。

作为旁注,我认为您需要使用属性标记属性以使用属性注入,但我可能会犯错(自从我直接使用Unity以来已经有一段时间了。)


编辑:您需要将DependencyAttribute应用于属性以在Unity中使用setter注入;你可以阅读here

答案 3 :(得分:0)

var modules = new IProductModule[]
{
    Container.Resolve<ProductAModule>()
    //Add more modules here...
};
Container.RegisterInstance<IProductModule[]>(modules);

就是这样!使用此代码,我可以将我的模块注入ShellViewModel并在我的应用程序中将每个模块显示为一个按钮!

这是一个简单的解决方案!来自CompositeWPF Discussion小组的好人。我推荐他们没有保留^ _ ^