2016-10-10 7 views
2

ViewModel (устанавливается через AutoWireViewModel="True") мой Shell/MainWindow запрашивает зависимость, которая будет загружаться в модуле при запуске с помощью ConfigurationModuleCatalog.
Поскольку оболочка инициализирована перед модулями, контейнер DI, очевидно, не может ее устранить, поэтому приложение аварийно завершает работу.Initialize Shell с ViewModel после загрузки всех модулей в Prism 6

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

Я уже попробовал два подхода this post, но оба не работали.

Я пробовал так:

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

Он начинает считать модули, а затем сбоя приложения из-за той же самой причине.
Если описанный выше подход не подходит для моей цели, как решить эту проблему?

Спасибо!

ответ

2

Я пытался реализовать Haukinger's предложение и сделал это таким образом, который работает просто отлично:

// 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); 
    } 
} 
+1

Чтобы отказаться от подписки, вы также можете сохранить токен подписки, возвращенный из 'Subscribe' и' Dispose'it, чтобы отказаться от подписки. – Haukinger

0

Я бы скрыть зависимость оболочки от фабрики/поставщика, а затем создать/извлечь ее, когда загружен последний модуль. Модель просмотра вашей оболочки подписывается на событие AllModulesLoaded, которое вызывается из вашего загрузочного файла InitializeModules, когда base.InitializeModules возвращается, чтобы получить уведомление о наличии зависимостей. Или завод/поставщик подписывается на событие, и оболочка опросит его, в зависимости от того, как вы хотите использовать зависимость.

+0

Спасибо за ваш ответ! Вы имеете в виду обычного участника мероприятия или PubSubEvent? Я не знаю, как работают/используются классы Factory. Не могли бы вы добавить в свой ответ короткий пример того, как я могу получить, например, IService через MainWindowViewModelFactory? –