2014-03-19 62 views
0

我想第一次使用Caliburn構建這個項目(也是MEF結構,我沒有完全理解)。具有多個視圖的Caliburn事件聚合器

我需要使用Conductor和EventAggregator。 導體,因爲我有一個AppViewModel「顯示」3個按鈕,將用戶移動到3個不同的視圖(AppView內的用戶控件)。

我需要EventAggregator,因爲這3個視圖中的一個必須加載第四個視圖(必須是我認爲的Window,而不是UserControl,因爲它必須是全屏)才能加載按鈕。 所以我認爲,當用戶在3視圖(AppView內部的UserControl)中單擊此按鈕時,Message可以發送到監聽器(應該是AppViewModel)的頂部,並且這個應該是ActivateItem(4th vm)。

我不明白爲什麼,但即使遵循Caliburn項目的示例,我的消息也沒有到達AppViewModel。

這是我的引導程序:

public class AppBootstrapper : Bootstrapper<AppViewModel> 
    { 
     private CompositionContainer container; 

     protected override void Configure() 
     { 
      container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => 
       new AssemblyCatalog(x)).OfType<ComposablePartCatalog>())); 

      CompositionBatch batch = new CompositionBatch(); 

      batch.AddExportedValue<IWindowManager>(new WindowManager()); 
      batch.AddExportedValue<IEventAggregator>(new EventAggregator()); 
      batch.AddExportedValue(container); 

      container.Compose(batch); 
     } 

     protected override object GetInstance(Type serviceType, string key) 
     { 
      string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key; 
      var exports = container.GetExportedValues<object>(contract); 

      if (exports.Any()) 
       return exports.First(); 

      throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract)); 
     } 

     protected override IEnumerable<object> GetAllInstances(Type serviceType) 
     { 
      return container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType)); 
     } 

     protected override void BuildUp(object instance) 
     { 
      container.SatisfyImportsOnce(instance); 
     } 

     protected override void OnStartup(object sender, StartupEventArgs e) 
     { 
      DisplayRootViewFor<AppViewModel>(); 
     } 
    } 

這是AppViewModel:

[Export (typeof(AppViewModel))] 
    public class AppViewModel : Conductor<object>, IHandle<ChangeViewEvent> 
    { 
     [ImportingConstructor] 
     public AppViewModel(IEventAggregator events) 
     { 
      events.Subscribe(this); 
      ActivateItem(new MainViewModel());    
     } 

     public void GoToPatientsManager() 
     { 
      ActivateItem(new PatientsManagerViewModel(new WindowManager(), new EventAggregator())); 
     } 

     public void GoToTestManager() 
     { 
      ActivateItem(new TestManagerViewModel(new WindowManager())); 
     } 

     public void GoToResultsManager() 
     { 
      ActivateItem(new MainViewModel()); 
     } 

     public void Handle(ChangeViewEvent message) 
     { 
      switch (message.ViewName) 
      { 
       case "TestManager" : 
        GoToTestManager(); 
        break; 
      } 
     } 
    } 

這是應該推出加載第四VM

[Export(typeof(PatientsManagerViewModel))] 
    public class PatientsManagerViewModel : Screen 
    { 
     private readonly IWindowManager _windowManager; 
     private readonly IEventAggregator eventAggregator; 

     [ImportingConstructor] 
     public PatientsManagerViewModel(IWindowManager windowManager, IEventAggregator eventAggregator) 
     { 
      _windowManager = windowManager; 
      this.eventAggregator = eventAggregator; 
     } 

     #region Methods 

     public void ShowFakeMessage() 
     { 
      dynamic settings = new ExpandoObject(); 
      settings.Placement = PlacementMode.Center; 
      settings.PlacementTarget = GetView(null); 

      var res = _windowManager.ShowDialog(new DeletePersonViewModel(), null, settings); 

      if (res) 
      { 
       // The result of the dialog men. In this true case we'll use Linq to delete the entry from the database 
       // using the dbContext 
      } 
     } 

     public void GoToTestManager() 
     { 
      eventAggregator.Publish(new ChangeViewEvent("TestManager")); 
     } 

     #endregion 
    } 
請求視圖模型

它沒有達到AppViewModel的Handle方法。

視圖模型的實例是否有這些錯誤?我不能從這裏向前邁進......

編輯

它可以是問題是,我通過每一次我激活新PatientsManagerViewModel新EventAggregator對象?有小費嗎?

回答

1

您診斷出自己的問題。您正在自己創建PatientsManagerViewModel,並且每次都傳入一個新的事件聚合器。這個想法是,事件聚合器必須是一個單例,即在所有視圖模型和其他所有模型之間共享的一個實例。這是因爲事件聚合器將訂戶存儲在內存中,並且新實例不知道誰要通知新事件,因爲沒有人會訂閱。

我建議你應該AppViewModel.GoToPatientsManager()看起來是這樣的:

public void GoToPatientsManager() 
{ 
    var patientManagerViewModel = IoC.Get<PatientsManagerViewModel>(); 
    ActivateItem(patientManagerViewModel); 
} 

國際奧委會是一個(相當醜陋,很難對其進行測試),您就可以訪問你的容器。你不應該自己創建視圖模型,而應該讓caliburn容器爲你做。如果容器創建了視圖模型,那麼它也將修復它對您的依賴關係,包括窗口管理器和事件聚合器。

相關問題