2017-05-20 17 views
0

(TLDR 버전은 아래입니다.) 프레임 워크로 IoC 및 Caliburn Micro로 MEF를 사용하여 WPF 응용 프로그램을 설계하고 있습니다.Caliburn Micro의 스크린 컨덕터와 함께 MEF 사용

다음

Main Window

는 윈도우의 뷰 모델입니다 : 응용 프로그램의 메인 화면은 다음과 같이이다

[Export(typeof(MainViewModel))] 
class MainViewModel : Conductor<PropertyChangedBase>, IHandle<ViewModelType> 
{ 
    private readonly IEventAggregator _eventAggregator; 

    private IEnumerable<Screen> _screenList { get; set; } 

    [ImportingConstructor] 
    public MainViewModel(IEventAggregator eventAggregator, [ImportMany]IEnumerable<Screen> screenList) 
    { 
     _screenList = screenList; 
     _eventAggregator = eventAggregator;      
     _eventAggregator.Subscribe(this); 
     ShowMenu(); 
    } 

    public void Handle(ViewModelType message) 
    {   
     ActivateItem(_screenList.FirstOrDefault(c => c.GetType() == message.VMtype)); 
     DisplayName = "B.I. Surgical & Dressing - " + (ActiveItem as Screen)?.DisplayName; 
     NotifyOfPropertyChange(() => CanShowMenu); 
    } 

    public void ShowMenu() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(Menu.MenuViewModel))); 
    public bool CanShowMenu => ActiveItem.GetType() != typeof(Menu.MenuViewModel); 
} 

그래서, _screenList 표시 할 필요로하는 모든 화면을 포함하고, 여기 있어요 표시 할 ViewModel을 나타내는 이벤트를 게시하는 MenuViewModel입니다.

[Export(typeof(MenuViewModel))] 
[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(Screen))] 
class MenuViewModel : Screen 
{ 
    private readonly IEventAggregator _eventAggregator;   

    [ImportingConstructor] 
    public MenuViewModel(IEventAggregator eventAggregator) 
    { 
     _eventAggregator = eventAggregator; 
     DisplayName = "Menu"; 
    } 

    public void CreateInvoice() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(Invoice.InvoiceViewModel))); 
    public void EnterPaymentsReceived() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(ReceivedPayments.PaymentsReceivedViewModel))); 
    public void EnterPurchases() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(PurchaseDetails.PurchaseDetailsViewModel))); 
    public void AddClientAndRates() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(AddClient.AddClientViewModel))); 
    public void EditClientAndRates() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(EditClient.EditClientViewModel))); 
    public void AddItem() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(AddItem.AddItemViewModel))); 
    public void EditItems() => _eventAggregator.PublishOnUIThread(new ViewModelType(typeof(EditItem.EditItemViewModel))); 

} 

그러나 문제는 f입니다. 이 라인은 MenuViewModel에있는 버튼을 클릭 할 때 새 VM을 얻는 대신,이 라인이 매번 ViewModel의 단일 인스턴스를 찾기 때문에 반복적으로 단일 인스턴스를 얻게됩니다. ActivateItem(_screenList.FirstOrDefault(c => c.GetType() == message.VMtype));

하지만 뷰가 비활성화 될 때마다 ViewModel을 처리해야합니다 (Screen 클래스의 OnDeactivate 메서드를 사용하여 뷰를 비활성화해야합니다). 그러나 매번 _screenList에서 ViewModel의 새로운 인스턴스를 얻는 방법을 모르겠습니다. 내 생각은 어떤 종류의 팩토리를 만드는 것이지만 MEF를 사용하여이를 구현하는 방법과 뷰가 비활성화 될 때마다 ViewModel을 처리하는 방법을 알지 못합니다.

SHORT VERSION :이이 [Export(typeof(Screen))] 특성으로 표시된 모든 구성 요소를 가져옵니다

private IEnumerable<Screen> _screenList { get; set; } 

[ImportingConstructor] 
public MainViewModel(IEventAggregator eventAggregator, [ImportMany]IEnumerable<Screen> screenList) 
{ 
    _screenList = screenList; 
} 

: -TLDR-

MEF에서, 나는 이런 식으로 뭔가를 할 수 있습니다. 그러나 각 구성 요소에는 [Export(typeof(ViewModelX))]과 같은 다른 속성이 표시됩니다. 기본적으로 Screen은 각 ViewModel을 파생시키는 기본 클래스입니다. 내 응용 프로그램에서

, 정말 같은 _screenList을 사용하고 있습니다 : ActivateItem(_screenList.FirstOrDefault(c => c.GetType() == typeof(ViewModelX)));

그러나, 내 문제에, 내가 원하는 _screenListViewModelX 때마다 새로운 인스턴스를 반환 할 수 있습니다. 어떻게해야합니까?

답변

0

마지막으로 문제의 해결책을 찾았습니다. ExportFactory을 사용하면 문제가 해결됩니다.

구현은 다음과 같다 :

private IEnumerable<ExportFactory<Screen>> _screenList { get; set; } 

[ImportingConstructor] 
public MainViewModel(IEventAggregator eventAggregator, [ImportMany] IEnumerable<ExportFactory<Screen>> screenList) 
{    
    _screenList = screenList; 
    _eventAggregator = eventAggregator;      
    _eventAggregator.Subscribe(this); 
    ShowMenu(); 
} 

public void Handle(ViewModelType message) 
{ 
    ActivateItem(_screenList.FirstOrDefault(c => c.CreateExport().Value.GetType() == message.VMtype).CreateExport().Value); 
}