3
votes

I have been trying to set up dependency injection in a wpf application using Unity, but can't seem to fully understand how the views and viewmodels should be set up.

Have looked into another SO post --> Wpf Unity but can't seem to understand it quite yet. I have used Unity before, but just in a MVC application, so I know how to inject it in the contructors.

Here is my views and viewModels in the application.

Views:

MainWindow.xaml
BookingView.xaml
ContactDetailsView.xaml
ReservationsView.xaml

ViewModels:

MenuViewModel (MainWindow uses this viewModel)
BookingViewModel
ContactViewModel
ReservationsViewModel

My ViewModels all have Interfaces implemented, like IMenuViewModel, should the view also have an interface?

I guess that since the MainWindow is the starting point, it should be here to register the container right?

Update:

Have found something, but not sure if I have done it right. Here is what I have done so far!

1: Using startup method in app.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        IUnityContainer container = new UnityContainer();

        container.RegisterType<IViewMainWindowViewModel, MainWindow>();
        container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();

        var mainWindow = container.Resolve<MainWindow>(); // Creating Main window
        mainWindow.Show();
    }

}

2: Remove uri from start up.

3: Make IViewMainWindowViewModel interface in MainWindow class, the interface is empty.

public interface IViewMainWindowViewModel
{

}

4: Make a reference to this interface in the MainWindow

public partial class MainWindow : Window, IViewMainWindowViewModel
{
    public MainWindow(IViewMainWindowViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }

5: Also for the MenuViewModel

public class MenuViewModel : IViewMainWindowViewModel
{
    Code not shown!
}

This will not even start the application..

Update 2

My MainWindow class look like this:

public interface IViewMainWindowViewModel
{

}

public partial class MainWindow : Window, IViewMainWindowViewModel
{
    public MainWindow(IViewMainWindowViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }

App class now look like this:

protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IViewMainWindowViewModel, MainWindow>();
        container.RegisterType<IViewMainWindowViewModel, MenuViewModel>();
        container.Resolve<MainWindow>().Show();
        //Do the same actions for  all views and their viewmodels
    }

I get an exception on this line when running the application

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

Update 3

In my MenuViewModel it has two command which will open two views, do I then need to inject those views in the MenuViewModel's constructor or can you just make another empty interface between MenuViewModel and BookingView as an example?

1

1 Answers

2
votes

Let me show an example with explanations just for your MainWindows, as for the rest views and viewmodels steps to do are the same.

At first, you should create a contract between View and ViewModel. It shoud be some interface and let it call IViewMainWindowViewModel (keep in mind that name has to be different for other view and viewModels, for example IViewBookingViewViewModel):

public interface IViewMainWindowViewModel
{
       /*This interface should not have any methods or commands. It is just 
       contract between View and ViewModels and helps to decide to Unity 
       container what it should inject(appropriate viewModel to necessary 
       View)*/
}

then in your viewmodel we should implement this interface:

public MenuViewModel:IViewMainWindowViewModel
{}

The view should inject this interface MainWindows.xaml.cs:

public partial class MainWindows : UserControl, IContentAView
{
    public MainWindows(IViewMainWindowViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;            
    }
 }

Delete StartupUri and override a method OnStartup in App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IViewMainWindowViewModel, MainWindow>();
    container.RegisterType<IViewMainWindowViewModel, MainWindowViewModel >();
    container.Resolve<MainWindow>().Show();
    //Do the same actions for  all views and their viewmodels
}