简体   繁体   中英

WPF MVVM with IUnityContainer creating unwanted multiple instances

Hi I am currently using WPF with the Model/View Pattern and IOC, however I am having a problem with that I currently have a 3 views of which only two will need to be created, determined at runtime.

In each view I am using the xaml to provide an object for the view like so:

ViewA

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

or

ViewB

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

...etc

Also these views and their subsequent models have a hierarchy like:

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

Now with IOC I am creating my container and registering an instance of the required model (either modelB or modelC). When trying to instantiate the views required, through container.resolve, either ViewA + ViewB or ViewA + ViewC.

I get multiple instantiations of the models.

When I only want 1 type to be created, either modelB or modelC.

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

The resolving of the views is generating more models when what I want is the container to use the already constructed instances of the model and inject this into the Views. Can anyone help or point me in the right direction,

Thanks,

Im not quite sure if Im on the right track but I'll see if I can help anyway.

Looking at the View/ModelB scenario the way I see what you have is:

  1. You register your single instance of ModelB with the UnityContainer
  2. You try to resolve a new ViewB
  3. A new instance of ModelB is created rather than the instance in step 1 being used

When a ViewB object is created it creates a new ModelB independently of the unity container. If you want the instance of ModelB that you previously registered in the unity container to be used you can pass it in as a dependency of ViewB eg

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

If you have this setup then when you try to Resolve a ViewB your previously registered ModelB will be passed in.

Hope that helps!

just incase anyone finds this later, and wants to know, I resolved this issue by basically taking out the static reference to the viewmodel in my views.

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

And as Scott suggests registered first the type, then an instance of that type, then resolving my inherrited view and subsequently the base view (which when called upon by the DI container injects in the registered type). Unfortunately this meant within VS2010 I could not use the designer to create the bindings in xaml, as I had to set the DataContext from code behind in the view constructor.

Code:

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

And then in the code behind for the views

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

This, like I say, resolved the issue but I hoped there would have been a cleaner way of using inherited views and their models. Of which I am still looking, but if that helps anyone else who is stuck on this, then great.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM