在Prism 6中加载所有模块后,用ViewModel初始化Shell

本文关键字:ViewModel Shell 初始化 模块 Prism 加载 | 更新日期: 2023-09-27 18:12:28

我的Shell/MainWindow的ViewModel(通过AutoWireViewModel="True"设置)请求一个依赖项,该依赖项在启动时使用ConfigurationModuleCatalog加载在模块中。
因为Shell是在模块之前初始化的,所以DI容器显然无法解决这个问题,所以应用程序会崩溃。

public class MainWindowViewModel : BindableBase
{
    // Cannot resolve IService
    public MainWindowViewModel(IService service)
    {
    }
}

我已经尝试了这篇文章的两种方法,但都不起作用。

我试过了:

public interface IShellService
{
    int NumberOfLoadedModules { get; }
    void FlagModuleAsLoaded();
}
public class ShellService : IShellService
{
    private readonly IModuleCatalog _moduleCatalog;
    public ShellService(IModuleCatalog moduleCatalog)
    {
        _moduleCatalog = moduleCatalog;
    }
    public int NumberOfLoadedModules { get; private set; }
    public void FlagModuleAsLoaded()
    {
        NumberOfLoadedModules++;
        if (NumberOfLoadedModules != _moduleCatalog.Modules.Count())
            return;
        InitializeShell();
    }
    private static void InitializeShell()
    {
         Application.Current.MainWindow.Show();
    }
}
internal class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return null;
    }
    protected override void InitializeShell()
    {
    }
    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
        Container.RegisterInstance<IShellService>(new ShellService(ModuleCatalog), new ContainerControlledLifetimeManager());
    }
    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new ConfigurationModuleCatalog();
    }
}

使用

public abstract class ModuleBase : IModule
{
    private readonly IShellService _shellService;
    protected ModuleBase(IShellService shellService)
    {
        _shellService = shellService;
    }
    public void Initialize()
    {
        InitializeInternal();
        FlagAsLoaded();
    }
    public abstract void InitializeInternal();
    public void FlagAsLoaded()
    {
        _shellService.FlagModuleAsLoaded();
    }
}
public class FooModule : ModuleBase
{
    IUnityContainer _container;
    public MusicUIModule(IUnityContainer container, IShellService shellService) : base(shellService)
    {
        _container = container;
    }
    public override void InitializeInternal()
    {
        _container.RegisterType<IService, Service>();
    }
}

它开始计数模块,然后应用程序崩溃,因为同样的原因。
如果上面的方法不适合我的目的,如何解决这个问题?

谢谢!

在Prism 6中加载所有模块后,用ViewModel初始化Shell

我尝试实现Haukinger的建议,并这样做了,工作得很好:

// Factory --------------------------------------------------------
public interface IDependencyFactory
{
    IService GetService();
}
public class DependencyFactory : IDependencyFactory
{
    private readonly IUnityContainer _container;
    public DependencyFactory(IUnityContainer container)
    {
        _container = container;
    }
    public IService GetService()
    {
        return _container.Resolve<IService>();
    }
}
// PubSubEvent ------------------------------------------------------
public class AllModulesLoaded : PubSubEvent
{
}
// Bootstrapper -----------------------------------------------------
internal class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }
    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }
    protected override void InitializeModules()
    {
        base.InitializeModules();
        // Publishing event to tell subscribers that the modules are loaded
        var eventAggregator = Container.Resolve<IEventAggregator>();
        eventAggregator?.GetEvent<AllModulesLoaded>().Publish();
    }
    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
        // ...
        Container.RegisterType<IDependencyFactory, DependencyFactory>();
    }
    protected override IModuleCatalog CreateModuleCatalog()
    {
        return new ConfigurationModuleCatalog();
    }
}
// ViewModel ---------------------------------------------------------
public class MainWindowViewModel : BindableBase
{
    private IService _service;
    private readonly IEventAggregator _eventAggregator;
    private readonly IDependencyFactory _dependencyFactory;
    public MainWindowViewModel(IEventAggregator eventAggregator, IDependencyFactory dependencyFactory)
    {
        _eventAggregator = eventAggregator;
        _dependencyFactory = dependencyFactory;
        _eventAggregator.GetEvent<AllModulesLoaded>().Subscribe(OnAllModulesLoaded);
    }
    private void OnAllModulesLoaded()
    {
        var service = _dependencyFactory.GetService();
        if (service != null)
            _service = service ;
        _eventAggregator.GetEvent<AllModulesLoaded>().Unsubscribe(OnAllModulesLoaded);
    }
}

我会隐藏在工厂/提供商后面的shell依赖,然后在最后一个模块加载时创建/获取它。您的shell的视图模型订阅了一个AllModulesLoaded事件,当base.InitializeModules返回以获得依赖可用的通知时,该事件从您的引导程序的InitializeModules触发。或者工厂/提供者订阅事件,然后shell轮询它,这取决于你想如何使用依赖项。