2017-05-20 8 views
0

(TLDR-Version ist unten.) Ich entwerfe eine WPF-Anwendung mit MEF als IoC und Caliburn Micro als Framework. Das Hauptfenster der Anwendung ist wie folgt aus:Verwendung von MEF mit Bildschirm-Leiter von Caliburn Micro

Main Window

Hier wird das Ansichtsmodell für das Fenster ist:

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

So _screenList enthält alle Bildschirme, und hier angezeigt werden muss, ist die MenuViewModel, die über ein Ereignis das Ansichtsmodell veröffentlicht werden angezeigt:

[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))); 

} 

Aber das Problem, das ich f bin Das ist, statt eine neue VM zu bekommen, wenn ich auf eine Schaltfläche in der MenuViewModel klicke, bekomme ich immer wieder eine einzelne Instanz, was eigentlich erwartet wird, weil diese Zeile jedesmal die einzelne Instanz des ViewModels findet: ActivateItem(_screenList.FirstOrDefault(c => c.GetType() == message.VMtype));

Aber ich muss das ViewModel immer wenn eine Ansicht deaktiviert ist (ich denke, ich muss das mit der OnDeactivate-Methode der Screen-Klasse tun). Aber ich weiß nicht, wie man jedes Mal eine neue Instanz eines ViewModels von _screenList bekommt. Meine Idee ist es, irgendeine Art von Factory zu erstellen, aber ich habe keine Ahnung, wie man das mit MEF implementiert und wie man ein ViewModel entsorgt, wenn die Ansicht deaktiviert ist.

KURZFASSUNG: -TLDR-

In MEF, kann ich so etwas wie dieses:

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

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

Dadurch werden alle Komponenten mit [Export(typeof(Screen))] Attribut gekennzeichnet importieren. Jede dieser Komponenten ist jedoch auch mit einem anderen Attribut wie [Export(typeof(ViewModelX))] gekennzeichnet. Grundsätzlich ist Screen die Basisklasse, von der die ViewModels abgeleitet sind.

In meiner Anwendung verwende ich _screenList wie so: ActivateItem(_screenList.FirstOrDefault(c => c.GetType() == typeof(ViewModelX)));

in meinem Problem jedoch, ich will _screenList eine neue Instanz eines ViewModelX jedes Mal zurück. Wie kann ich das machen?

Antwort

0

Schließlich, eine Lösung für das Problem gefunden. Die Verwendung des ExportFactory löste das Problem.

Die Umsetzung wird wie folgt:

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); 
} 
Verwandte Themen