Silverlight ViewModelLocator, определенный в app.xaml, нуждается в ссылке на контейнер DI

У меня есть класс ViewModelLocator, который я определяю в app.xaml, который используется моими представлениями для привязки данных к правильному ViewModel.

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

Я использую Prism и Unity, и мой класс ViewModelLocator нуждается в ссылке на контейнер уровня приложения.

Я хотел внедрить IUnityContainer в ctor ViewModelLocator, но ViewModelLocator создается из app.xaml с использованием ctor без параметров.

Есть ли предпочтительный способ получить доступ к контейнеру уровня приложения - для всех других классов в приложении я просто использую инъекцию ctor, чтобы получить глобальный контейнер.

То, что я сейчас делаю для ViewModelLocator, - это определение статической переменной в моем классе BootStrapper для хранения контейнера. Я создаю контейнер, переопределяя метод CreateContainer на UnityBootStrapper.

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

Затем в классе ViewModelLocator я просто ссылаюсь на свойство BootStrapper.DIContainer, чтобы зарегистрировать мои модели представления

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

Это прекрасно работает, но это единственное место в приложении, которое должно ссылаться на это статическое свойство в загрузчике - и хотело бы избавиться от него, если это возможно.

спасибо Майкл

2 ответа

У меня была такая же проблема при преобразовании моего приложения Silverlight RIA Business для использования легкого инструментария Prism, Unity и MVVM. Я придумал этот обходной путь, который заключается в том, чтобы просто позволить App.xaml создать экземпляр моего класса ViewModelLocator, и во время события запуска приложения я удаляю тот экземпляр, который он создал, из ресурсов приложения и повторно добавляю экземпляр, используя метод Resolve контейнера Unity.

  1. Зарегистрируйте VML в Unity.

Boostrapper.cs: (класс UnityBootstrapper)

protected override void ConfigureContainer()
{
    Container.RegisterType<ViewModelLocator>(new ContainerControlledLifetimeManager());
    base.ConfigureContainer();
}
  1. Используйте конструктор или внедрение свойства в VML для IUnityContainer. Здесь я использую свойство инъекции. Также обратите внимание, что конструктор по умолчанию без параметров необходим, потому что App.xaml собирается создать свой собственный экземпляр, который мы просто выбросим.

ViewModelLocator.cs: (используется для смешиваемости)

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

    public ViewModelLocator() { }

....

}

  1. Удалите и повторно добавьте VML к ресурсам приложения. Замените строковый литерал "Локатор" тем, что вы называете своим VML в разделе ResourceDictionary App.xaml.

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>());
}

Твой теперь взведен, заперт, и готов качаться..

Я думал, что буду следить за этим, так как он не был отмечен как ответ.

Я придерживался аналогичного подхода к Degree451, за исключением того, что я не удаляю и не добавляю локатор заново, так как он немного пахнет. Вместо этого я использую встроенные возможности как Silverlight, так и Unity для решения проблемы.

Наличие свойства Container в классе ViewModelLocator, помеченном DependencyAttribute, означает, что класс может иметь свои зависимости, разрешенные после создания экземпляра. Поэтому в моем загрузчике я перезаписываю ConfigureContainer и добавляю следующий код:

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

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

В первой строке извлекается экземпляр, автоматически созданный приложением, из разметки App.xaml. Вторая строка использует Unity для разрешения любых свойств, помеченных атрибутом DependencyAttribute.

Для меня это намного более чистое решение. Конечно, это не смешиваемо.

Другие вопросы по тегам