CipherShark
CipherShark

Reputation: 81

Using Ninject as the DI Container with Calburn.Micro and MVVM in WPF

All I have some experience with Caliburn.Micro using System.ComponentModel.Composition as an IoC container. This time I want to have some fun and use Niject. To setup the Calburn.Micro bootstrapper, I have the following class

public class Bootstrapper : BootstrapperBase
{
    private IKernel _kernel;

    public Bootstrapper()
    {
        Initialize();
    }

    protected override void Configure()
    {
        _kernel = new StandardKernel();
        _kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
        _kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
        _kernel.Bind<IMainWindowViewModel>().To<MainWindowViewModel>().InSingletonScope();
    }

    protected override object GetInstance(Type service, string key)
    {
        return _kernel.Get(service);
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _kernel.GetAll(service);
    }

    protected override void OnStartup(object sender, StartupEventArgs suea)
    {
        base.OnStartup(sender, suea);
        DisplayRootViewFor<IMainWindowViewModel>();
    }

    protected override void OnExit(object sender, EventArgs e)
    {
        _kernel.Dispose();
        base.OnExit(sender, e);
    }
}

This seem to be called fine, but when the line

DisplayRootViewFor<IMainWindowViewModel>();

Is hit, it seems to launch the view IMainWindowView okay, but

public partial class MainWindowView : Window
{
    public MainWindowView()
    {
        InitializeComponent();
    }
}

public interface IMainWindowViewModel { }

and MainWindowViewModel as

public class MainWindowViewModel : Conductor<IMainWindowViewModel>, IMainWindowViewModel { }

with the XAML of IMainWindowView as

<Window x:Class="Mole.Replay.Framework.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:ViewModels="clr-namespace:Mole.Replay.Framework"
        xmlns:local="clr-namespace:Mole.Replay.Framework"
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
    <Window.DataContext>
        <ViewModels:MainWindowView/>
    </Window.DataContext>
    <Grid>

    </Grid>
</Window>

The ctor is called over and over again and results in a StackOverflow exception, there is no clear cause for this what-so-ever. This type is bound in singleton scope. Why is this happening am I missing something?

Upvotes: 1

Views: 120

Answers (1)

ASh
ASh

Reputation: 35681

<Window.DataContext>
    <ViewModels:MainWindowView/>
</Window.DataContext>

it doesn't make sense to set DataContext of MainWindowView to another instance of MainWindowView which will also try to set DataContext etc, until you get StackOverflow exception.

it should be a view model in DataContext. I don't know if caliburn.micro creates view models for view based on conventions, but at least remove current <Window.DataContext> assignment.

it is not clear to me why view namespace is aliased as ViewModels. If real view model is in the same namespace and it is not resolved automatically, assign view model

<Window.DataContext>
    <ViewModels:MainWindowViewModel/>
</Window.DataContext>

DI container really should provide constructor arguments.Use them to assign DataContext:

public MainWindowView(IMainWindowViewModel vm)
{
    InitializeComponent();
    DataContext = vm;
}

Upvotes: 2

Related Questions