WPF MVVM с IUnityContainer создает нежелательные множественные экземпляры

Привет! В настоящее время я использую WPF с шаблоном Model/View и IOC, однако у меня возникла проблема с тем, что в настоящее время у меня есть 3 представления, из которых необходимо создать только два, определенные во время выполнения.

В каждом представлении я использую xaml для предоставления объекта для представления следующим образом:

ViewA

<viewmodel:modelA x:Key="viewModel"/>

или же

ViewB

<viewmodel:modelB x:Key="viewModel"/>

...так далее

Также эти представления и их последующие модели имеют следующую иерархию:

class modelA          { public virtual  ConfigA    {get; set;}   } 
class modelB : modelA { public override ConfigB    {get; set;}   }
class modelC : modelB { public override ConfigC    {get; set;}   }

class ConfigA           { public int Test  { get; set;} } 
class ConfigB : ConfigA { public int TestA { get; set;} } 
class ConfigC : ConfigC { public int TestB { get; set;} } 

Теперь с помощью IOC я создаю свой контейнер и регистрирую экземпляр требуемой модели (либо modelB, либо modelC). При попытке создать необходимые представления через container.resolve либо ViewA + ViewB, либо ViewA + ViewC.

Я получаю несколько экземпляров моделей.

Когда я хочу создать только 1 тип, то модель B или модель C.

switch (Object)
{
  case 1:
    modelB b = new modelB();
    Container.RegisterInstance<modelB>(b, new ContainerControlledLifetimeManager());
    RegionManager.Regions[RegionNames.MainRegion].Add(Container.Resolve<ViewB>());
  break;
  case 1:
    modelC c = new modelC();
    Container.RegisterInstance<modelC>(c, new ContainerControlledLifetimeManager());
    RegionManager.Regions[RegionNames.MainRegion].Add(Container.Resolve<ViewC>());
  break;
}
RegionManager.Regions[RegionNames.MainRegion].Add(Container.Resolve<ViewA>());

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

Спасибо,

2 ответа

Я не совсем уверен, нахожусь ли я на правильном пути, но я посмотрю, смогу ли я все равно помочь.

Глядя на сценарий View/ModelB, я вижу то, что у вас есть:

  1. Вы регистрируете свой единственный экземпляр ModelB в UnityContainer.
  2. Вы пытаетесь разрешить новый ViewB
  3. Создается новый экземпляр ModelB, а не экземпляр на шаге 1

Когда создается объект ViewB, он создает новый ModelB независимо от контейнера единицы. Если вы хотите использовать экземпляр ModelB, который вы ранее зарегистрировали в контейнере Unity, вы можете передать его как зависимость от ViewB, например:

public class ViewB
{
    public ViewB(ModelB model){ .. }
}

Если у вас есть эта настройка, то, когда вы попытаетесь разрешить ViewB, ваш ранее зарегистрированный ModelB будет передан.

Надеюсь, это поможет!

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

<viewmodel:modelB x:Key="viewModel"/>

И, как Скотт предлагает сначала зарегистрировать тип, затем экземпляр этого типа, затем разрешить мое унаследованное представление и впоследствии базовое представление (которое при вызове контейнера DI внедряет в зарегистрированный тип). К сожалению, это означало, что в VS2010 я не мог использовать конструктор для создания привязок в xaml, так как мне пришлось установить DataContext из кода в конструкторе представления.

Код:

  UserControl view = null;
  switch (runtimeSetArg)
  {
    case 1:
      Container.RegisterType<modelA, modelB>(new ContainerControlledLifetimeManager());
      Container.RegisterInstance<modelB>(new modelB());
      view = Container.Resolve<viewB>();
      break;
    case 2:
      Container.RegisterType<modelA, modelC>(new ContainerControlledLifetimeManager());
      Container.RegisterInstance<modelC>(new modelC());
      view = Container.Resolve<viewC>();
      break;
    case 3:
      ...
      break;
    case default:
      break;
  }

  if (view != null)
  {
    RegionManager.Regions[RegionNames.MainRegion].Add(Container.Resolve<viewA>());        
    RegionManager.Regions[RegionNames.MainRegion].Add(view);
  }

А потом в коде позади для просмотров

public partial class ViewB: UserControl
{
  public ViewB(IUnityContainer container)
  {
    this.DataContext = (ModelB)container.Resolve<ModelB>();      
    InitializeComponent();
  }
}

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

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