C# 使用ModernUI和x2B重新实现WindowManager;卡利本。微组合

C# 使用ModernUI和x2B重新实现WindowManager;卡利本。微组合,c#,.net,dependency-injection,caliburn.micro,modern-ui,C#,.net,Dependency Injection,Caliburn.micro,Modern Ui,Caliburn.Micro与ModernUI成功结合。 但是如果我们想使用多个窗口,我们还需要重新实现Caliburn的WindowManager,以便与ModernUI正常工作。怎样才能做到呢 更新: (关于IoC容器/依赖项注入的附加问题) 好的,我明白了:我在这里使用了构造函数注入: public class BuildingsViewModel : Conductor<IScreen> { public BuildingsViewModel(IWindowMana

Caliburn.Micro与ModernUI成功结合。 但是如果我们想使用多个窗口,我们还需要重新实现Caliburn的
WindowManager
,以便与ModernUI正常工作。怎样才能做到呢

更新: (关于IoC容器/依赖项注入的附加问题)

好的,我明白了:我在这里使用了构造函数注入:

public class BuildingsViewModel : Conductor<IScreen>

{
    public BuildingsViewModel(IWindowManager _windowManager)
    {
        windowManager = _windowManager;
    }
}
如果我从容器中解析一个对象实例,它将注入所有需要的依赖项。像一棵树

1) 所以现在我想知道如何使用注入(带接口)替换这一行?
\u windowManager.ShowWindow(新的PopupViewModel())

2) 若我想让整个项目匹配DI模式,所有对象实例都必须注入到
ModernWindowViewModel
,首先从容器解析

3) 整个项目可以使用Caliburn的
SimpleContainer
,还是更好地使用Castle Windsor这样的成熟框架?我应该避免混合吗

更新2:

public void SomeMethod()
{
    _windowManager.ShowWindow(new PopupViewModel()); // Or use injection etc
}
public partial class IntegrationService : ServiceBase
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public IntegrationService()
    {
        InitializeComponent();

        _bootstrapper = new Bootstrapper();
    }

    protected override void OnStart(string[] args)
    {
        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();

        if (_engine == null)
            Stop();
        else
            _engine.Start();
    }

    protected override void OnStop()
    {
        if (_engine != null)
            _engine.Stop();
    }
}
public class ConsoleAppExample
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public ConsoleAppExample()
    {
        _bootstrapper = new Bootstrapper();

        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();
        _engine.Start();
    }
}

4) 将IoC容器集成到现有应用程序中需要首先创建此容器(例如在console app的
Main()
方法中),然后所有对象实例都必须通过注入的依赖项从中增长?

只需创建您自己的派生
WindowManager
并覆盖
EnsureWindow

public class ModernWindowManager : WindowManager
{
    protected override Window EnsureWindow(object rootModel, object view, bool isDialog)
    {
        var window = view as ModernWindow;

        if (window == null)
        {
            window = new ModernWindow();
            window.SetValue(View.IsGeneratedProperty, true);
        }

        return window;
    }
}
要用作弹出窗口的任何视图必须基于
ModernWindow
,并且必须使用
LinkGroupCollection
,或者必须设置窗口的
ContentSource
属性,否则将没有内容

您可以使用上述方法使此
视图优先
,但它可以
视图模型优先

e、 g.要弹出我的
PopupView
,我执行了以下操作

PopupView.xaml

<mui:ModernWindow x:Class="TestModernUI.ViewModels.PopupView"
             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:mui="http://firstfloorsoftware.com/ModernUI"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" ContentSource="/ViewModels/ChildView.xaml">
 </mui:ModernWindow>
从另一个ViewModel弹出视图的代码:

public void SomeMethod()
{
    _windowManager.ShowWindow(new PopupViewModel()); // Or use injection etc
}
public partial class IntegrationService : ServiceBase
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public IntegrationService()
    {
        InitializeComponent();

        _bootstrapper = new Bootstrapper();
    }

    protected override void OnStart(string[] args)
    {
        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();

        if (_engine == null)
            Stop();
        else
            _engine.Start();
    }

    protected override void OnStop()
    {
        if (_engine != null)
            _engine.Stop();
    }
}
public class ConsoleAppExample
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public ConsoleAppExample()
    {
        _bootstrapper = new Bootstrapper();

        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();
        _engine.Start();
    }
}
不要忘记在您的容器中注册
ModernWindowManager
以代替
WindowManager

例如使用CM的SimpleContainer

container.Singleton<IWindowManager, ModernWindowManager>();
我的视图的完整名称空间是
TestModernUI.ViewModels.PopupView
,生成的URI是
/ViewModels/PopupView.xaml
,然后通过内容加载器自动加载和绑定

更新2

仅供参考这里是我的
引导程序
配置方法:

protected override void Configure()  
{
    container = new SimpleContainer();

    container.Singleton<IWindowManager, ModernWindowManager>();
    container.Singleton<IEventAggregator, EventAggregator>();
    container.PerRequest<ChildViewModel>();
    container.PerRequest<ModernWindowViewModel>();
    container.PerRequest<IShell, ModernWindowViewModel>();
}
唯一的缺点是,如果您需要在同一个viewmodel中多次使用该实例,则该实例将是相同的,不过如果您知道同时需要多少实例,则可以注入多个
PopupViewModel

使用某种形式的按需注入

对于以后需要的依赖项,可以使用按需注入,例如工厂

我认为Caliburn或SimpleContainer不支持开箱即用的工厂,因此替代方法是使用
IoC.Get
IoC
是一个静态类,它允许您在实例化后访问DI容器

 public void ShowPopup()
 {
     var popup = IoC.Get<PopupViewModel>();
     _windowManager.ShowWindow(popup);
 }
Windsor支持工厂,这样您就可以
解析
发布
您的组件,并更明确地管理它们的生命周期,但我在此不赘述

2)如果我想让整个项目匹配DI模式,所有对象实例都必须注入ModernWindowViewModel,该模型首先从容器解析?

您只需要注入
ModernWindowViewModel
所需的依赖项。儿童需要的任何内容都会自动解析和注入,例如:

public class ParentViewModel
{
    private ChildViewModel _child;

    public ParentViewModel(ChildViewModel child)
    {
        _child = child;
    }
}

public class ChildViewModel
{
    private IWindowManager _windowManager;
    private IEventAggregator _eventAggregator;

    public ChildViewModel(IWindowManager windowManager, IEventAggregator eventAggregator) 
    {
        _windowManager = windowManager;
        _eventAggregator = eventAggregator;
    }
}
在上述情况下,如果从容器中解析
ParentViewModel
ChildViewModel
将获得其所有依赖项。您不需要将它们注入父级

3)整个项目可以使用Caliburn的SimpleContainer,还是更好地使用Castle Windsor这样的成熟框架?我应该避免混合吗?

您可以混合,但可能会混淆,因为它们彼此不起作用(一个容器不知道另一个容器)。只需使用一个容器,
SimpleContainer
就可以了-Castle Windsor有很多功能,但您可能永远都不需要它们(我只使用了一些高级功能)

4)将IoC容器集成到现有应用程序中需要首先创建此容器(例如,在console app的Main()方法中),然后所有对象实例都必须通过注入依赖项从中增长?

是的,您创建容器,然后解析根组件(在99.9%的应用程序中有一个主组件称为组合根),然后构建完整的树

下面是一个用于基于服务的应用程序的引导程序示例。我正在使用Castle Windsor,我希望能够在Windows服务、WPF应用程序甚至控制台窗口(用于测试/调试)中托管引擎:

控制台应用程序:

public void SomeMethod()
{
    _windowManager.ShowWindow(new PopupViewModel()); // Or use injection etc
}
public partial class IntegrationService : ServiceBase
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public IntegrationService()
    {
        InitializeComponent();

        _bootstrapper = new Bootstrapper();
    }

    protected override void OnStart(string[] args)
    {
        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();

        if (_engine == null)
            Stop();
        else
            _engine.Start();
    }

    protected override void OnStop()
    {
        if (_engine != null)
            _engine.Stop();
    }
}
public class ConsoleAppExample
{
    private readonly Bootstrapper _bootstrapper;

    private IIntegrationEngine _engine;

    public ConsoleAppExample()
    {
        _bootstrapper = new Bootstrapper();

        // Resolve the engine which resolves all dependencies
        _engine = _bootstrapper.GetEngine();
        _engine.Start();
    }
}
以下是IIntegrationEngine实施的一部分

public class IntegrationEngine : IIntegrationEngine
{
    private readonly IScheduler _scheduler;
    private readonly ICommsService _commsService;
    private readonly IEngineStateService _engineState;
    private readonly IEnumerable<IEngineComponent> _components;
    private readonly ConfigurationManager _configurationManager;
    private readonly ILogService _logService;

    public IntegrationEngine(ICommsService commsService, IEngineStateService engineState, IEnumerable<IEngineComponent> components,
        ConfigurationManager configurationManager, ILogService logService)
    {
        _commsService = commsService;
        _engineState = engineState;
        _components = components;
        _configurationManager = configurationManager;
        _logService = logService;

        // The comms service needs to be running all the time, so start that up
        commsService.Start();
    }
公共类集成引擎:IIntegrationEngine
{
专用只读isScheduler\u调度器;
专用只读ICommsService(公共服务);;
私人只读IEngineStateService(引擎地产);
私有只读IEnumerable\u组件;
专用只读配置管理器\u配置管理器;
专用只读ILogService(日志服务);;
公共集成引擎(ICommsService commsService、IEEngineStateService engineState、IEnumerable components、,
配置管理器配置管理器,ILogService日志服务)
{
_commsService=commsService;
_engineState=engineState;
_组件=组件;
_configurationManager=configurationManager;
_logService=logService;
//通信服务需要一直运行,所以启动它