首页 > 解决方案 > 在 WPF 中使用 Ninject 作为带有 Calburn.Micro 和 MVVM 的 DI 容器

问题描述

我对使用 Caliburn.MicroSystem.ComponentModel.Composition作为 IoC 容器有一些经验。这次我想找点乐子并使用 Niject。要设置 Calburn.Micro 引导程序,我有以下课程

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

这似乎被称为罚款,但当线

DisplayRootViewFor<IMainWindowViewModel>();

被击中了,好像启动视图IMainWindowView还行,但是

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

public interface IMainWindowViewModel { }

并且MainWindowViewModel作为

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

XAML 为IMainWindowViewas

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

ctor 被一遍又一遍地调用并导致 StackOverflow 异常,没有明确的原因导致这种情况。此类型绑定在单例范围内。为什么会发生这种情况我错过了什么?

标签: c#wpfninjectcaliburn.micro

解决方案


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

将 MainWindowView 的 DataContext 设置为 MainWindowView 的另一个实例是没有意义的,该实例也将尝试设置 DataContext 等,直到你得到 StackOverflow 异常。

它应该是 DataContext 中的视图模型。我不知道 caliburn.micro 是否根据约定为视图创建视图模型,但至少删除当前<Window.DataContext>分配。

我不清楚为什么视图命名空间被别名为 ViewModels。如果真实视图模型在同一个命名空间中并且没有自动解析,则分配视图模型

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

DI 容器确实应该提供构造函数参数。使用它们来分配 DataContext:

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

推荐阅读