2014-03-19 4 views
0

처음으로 Caliburn을 사용하여이 프로젝트를 작성하려고합니다. 완전히 이해하지 못했던 MEF 구조도 작성했습니다.여러보기가있는 Caliburn 이벤트 집계 도구

지휘자와 EventAggregator를 모두 사용해야합니다. 나는 3 개의 다른보기 (AppView 내부의 UserControls)로 사용자를 이동시키는 3 개의 버튼을 "표시"하는 AppViewModel을 가지고 있기 때문에 도체가 있습니다.

그리고 이러한 3 개의보기 중 하나에 4 번째보기를로드해야하는 단추가 있기 때문에 EventAggregator가 필요합니다. 전체 화면이어야하기 때문에 UserControl이 아닌 생각하는 창이어야합니다. 그래서 나는 사용자가 3 개의 뷰 (AppView 내부의 UserControl)에서이 버튼을 클릭하면 메시지가 Listener (즉, AppViewModel이어야 함) 위로 전송 될 수 있다고 생각했습니다.이 메시지는 ActivateItem (4 번째 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; 
      } 
     } 
    } 

그리고 이것은 4 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 메서드에 도달하지 않습니다.

보기 모델의 인스턴스에 이러한 문제가 있습니까? 나는

편집

은 문제가 나는 새로운 EventAggregator 오브젝트 나는 새로운 PatientsManagerViewModel을 활성화 할 때마다 통과한다는 것을 수 있습니다 ... 여기에서 앞으로 이동할 수 없습니다? 어떤 팁?

답변

1

당신은 자신의 문제를 진단했습니다. 매번 PatientsManagerViewModel을 만들고 매번 새 이벤트 수집기를 전달합니다. 아이디어는 이벤트 애그리 게이터가 모든 뷰 모델과 그 밖의 모든 것 사이에서 공유되는 단일 인스턴스, 즉 하나의 인스턴스 여야한다는 것입니다. 이는 이벤트 집계 기가 등록자를 메모리에 저장하고 새 인스턴스는 아무도 구독하지 않으므로 새로운 이벤트를 알리는 사람을 알 수 없기 때문입니다.

나는 당신의 AppViewModel.GoToPatientsManager()은 다음과 같이 보일 것을 제안 :

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

의 IoC는 컨테이너에 액세스 할 수있는 (아주 못생긴, 하드 테스트하는) 방법입니다. 뷰 모델을 직접 만들어서는 안되며 대신 caliburn 컨테이너로 대신해야합니다. 컨테이너가 뷰 모델을 생성하면 윈도우 매니저와 이벤트 애그리 게이터를 포함하여 자신이 가지고있는 종속성도 수정합니다.