0

I'm writing a WPF application using Unity as Ioc for Dependency Injection

I create my main window with:

container.RegisterType<IMainWindow, MainWindow>();
container.RegisterType<ISecondWindow, SecondWindow>();

container.Resolve<IMainWindow>().Show();

All other windows are injected with Dependency injection, for example in my "MainWindow" i can open trough a button my "SecondWindow",so i have ISecondWindow in the MainWindow constructor

public partial class MainWindow: Window, IMainWindow
{
    public MainWindow(IMainWindowViewModel viewModel, ISecondWindow secondWindow)
    {
        //with this solution I can open the second window from IMainWindowViewModel (viewmodels has no reference to windows which are in a separate project)
        viewModel.OpenSecondWindow += (s,e) => secondWindow.Show();
    }

SecondWindow has not other windows so it defines only ViewModels in his constructor

public partial class SecondWindow: Window, ISecondWindow
{
    public SecondWindow(ISecondWindowViewModel viewModel)

all the dependencies are then resolved in cascade (WINDOW -> VIEWMODEL -> SERVICE -> REPOSITORY)

This perfectly works until i have only one instance of my second window, but...

what about if I can have N windows/instance of my ISecondWindow opened at same time (for example I have a list, I double click on first row and an ISecondWindow is open with first row details, then i double click on second row and ANOTHER ISecondWindow is open with second row details (so I can view first and second row details at the same time))?

with DI this can't be accomplished, because I have and can use only one instance of my ISecondWindow.

Only solution which I have in my mind to solving this problem is using Service locator, but Service locator is an anti pattern and i wouldn't use it.

Do you have any ideas/seuggestion to solve this?

Proxymus89
  • 15
  • 3
  • Can you include your current method of `ISecondWindow` registration that is not working, please? – Nathan Werry Dec 07 '18 at 16:27
  • What benefit are you getting from injecting the second window into your main window? IIRC frameworks like MVVM cross use reflection to establish which window is linked to the VM. The primary benefit of DI is testing - but injecting one window into another still leaves you with a UI element to test. – Paul Michaels Dec 07 '18 at 16:30
  • i updated my sample. The benefit obviously are that all dependencies of SecondWindow are injected in cascade (ISecondWindow -> ISecondWindowViewModel -> ISecondWindowService -> ISecondWindowRepository etc.) – Proxymus89 Dec 07 '18 at 16:46
  • You mention:that your WPF app does not have to know about the existence of your container, what is your reasoning against this? Because I think if you just call `container.Resolve()` each time you make a new window, you will get what you need, instead of passing it in the constructor. – Nathan Werry Dec 07 '18 at 17:01
  • @NathanWerry because container should be used only in composition root, use it out of composition root is like as Service locator -> anti pattern "In case you use a DI Container, the Composition Root should be the only place where you use the DI Container. Using a DI Container outside the Composition Root leads to the Service Locator anti-pattern" https://freecontent.manning.com/dependency-injection-in-net-2nd-edition-understanding-the-composition-root/ https://stackoverflow.com/questions/6277771/what-is-a-composition-root-in-the-context-of-dependency-injection – Proxymus89 Dec 08 '18 at 09:59

1 Answers1

1

Try registering your ISecondWindow using a TransientLifetimeManager.

http://www.tutorialsteacher.com/ioc/lifetime-manager-in-unity-container

Connell.O'Donnell
  • 3,603
  • 11
  • 27
  • 61
  • but this make me use my container as a Service Locator and my WPF project does not have to know about the existence of the container – Proxymus89 Dec 07 '18 at 16:38
  • There will be no changes in your constructor `public MainWindow(IMainWindowViewModel viewModel, ISecondWindow secondWindow)` in this case – Belurd Dec 07 '18 at 18:35
  • In fact, you already using it, because it is default: `TransientLifetimeManager is the default lifetime manager.It creates a new object of requested type every time you call Resolve() or ResolveAll() method.` In your case this happends in constructor. – Belurd Dec 07 '18 at 18:39