(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
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?