app.xaml中定义的Silverlight ViewModelLocator需要对DI容器的引用

时间:2010-09-02 19:20:43

标签: silverlight dependency-injection blendability

我有一个我在app.xaml中定义的ViewModelLocator类,我的视图使用它来将数据绑定到正确的ViewModel。

DataContext="{Binding HomeViewModel, Source={StaticResource Locator}}"

我正在使用Prism和Unity,我的ViewModelLocator类需要对应用程序级统一容器的引用。

我想将IUnityContainer注入ViewModelLocator的ctor,但ViewModelLocator使用无参数ctor从app.xaml获得实例化。

是否有一种首选的方式来访问应用程序级容器 - 对于应用程序中的所有其他类,我只使用ctor注入来获取全局容器。

我目前正在为ViewModelLocator做的是在我的BootStrapper类中定义一个静态变量来存储容器。我通过覆盖UnityBootStrapper上的CreateContainer方法来创建容器。

protected override IUnityContainer CreateContainer()
{
    BootStrapper.DIContainer = base.CreateContainer();
    return BootStrapper.DIContainer;
}

然后在 ViewModelLocator 类中,我只引用BootStrapper.DIContainer属性来注册我的viewmodels

BootStrapper.DIContainer.RegisterType<IShellViewModel, DesignShellViewModel>();

这很好但是它是应用程序中唯一需要在引导程序上引用此静态属性的地方 - 并且如果可能的话想要删除它。

感谢 迈克尔

2 个答案:

答案 0 :(得分:1)

在将我的Silverlight RIA Business应用程序转换为使用Prism,Unity和MVVM light工具包时,我遇到了同样的问题。我提出了这个解决方法,即让App.xaml创建我的ViewModelLocator类的实例,并在应用程序启动事件期间,我从应用程序资源中删除它创建的实例,并使用Unity容器的重新添加实例解决方法。

  1. 向Unity注册VML。
  2. Boostrapper.cs :( UnityBootstrapper类)

    protected override void ConfigureContainer()
    {
        Container.RegisterType<ViewModelLocator>(new ContainerControlledLifetimeManager());
        base.ConfigureContainer();
    }
    
    1. 在VML for IUnityContainer中使用构造函数或属性注入。在这里,我正在使用属性注入。另请注意,默认的无参数构造函数是必需的,因为App.xaml将实例化它自己的实例,我们最终会抛弃它。
    2. ViewModelLocator.cs :(用于可混合性)

      public class ViewModelLocator
      {
          [Dependency]
          public IUnityContainer Container { get; set; }
      
          public ViewModelLocator() { }
      
      ....
      

      }

      1. 删除并重新添加VML到应用程序资源。将字符串文字“Locator”替换为App.xaml ResourceDictionary部分中您称为VML的内容。
      2. App.xaml.cs:

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            Bootstrapper bootstrapper = new Bootstrapper();
            bootstrapper.Run();
        
            Resources.Remove("Locator");
            Resources.Add("Locator", bootstrapper.Container.Resolve<ViewModelLocator>());
        }
        

        你现在翘起,锁定,准备摇滚..

答案 1 :(得分:0)

我以为我会对此进行跟进,因为它没有被标记为已回答。

我对Degree451采用了类似的方法,除了我没有删除并重新添加定位器,因为它有点味道。相反,我使用Silverlight和Unity的内置功能来处理问题。

在ViewModelLocator类中使用DependencyAttribute标记Container属性意味着该类可以在实例化后解析其依赖项。所以在我的Bootstrapper中,我重写了ConfigureContainer并添加以下代码:

var vml = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;

Container.BuildUp(typeof(ViewModelLocator), vml);

第一行检索应用程序从App.xaml标记自动创建的实例。第二行使用Unity来解析使用DependencyAttribute标记的任何属性。

对我来说,这是一个更清洁的解决方案。当然,它不是Blendable。