Entwickler-Ecke
WPF / Silverlight - MVVMLightToolkit neue ViewModel Instanz
Yankyy02 - Mo 04.09.17 21:07
Titel: MVVMLightToolkit neue ViewModel Instanz
Hallo liebe Gemeinde der Entwickler-Ecke,
ich möchte meine nächste Anwendung in verbindung mit dem MVVM Light Toolkit umsetzen. Der Einstieg fällt einem nicht schwer da es ja mehrere Tutorials im Netz dazu gibt. Ich möchte allerdings jedesmal wenn ich eine View (Fenster) aufrufe das mir eine neue Instanz des zugehörigen ViewModels erstellt wird. Auch dazu gibt es einige Ansätze im Netz allerdings wirken diese nicht recht überzeugend auf mich da es eher Beispiele alla ... ich würde es halt so machen ... sind! Meine Frage ist nun ob jemand mit dem Toolkit bereits eine Anwendung umgesetzt hat bzw. vor dem selben Problem gestanden hat und mir nun sagen kann wie ich am besten vorgehen soll. Oder ist es doch so das man die Instanz des jeweiligen ViewModels über die ganze Laufzeit der Anwendung aufrecht erhalten sollte?
Im Anhang findet Ihr ein Beispielprojekt wie ich es mir vorgestellt bzw. aktuell umgesetzt habe.
Die relevanten Codeteile sind folgende .....
XML-Daten
1: 2: 3: 4: 5: 6:
| DataContext="{Binding PersonViewModel, Source={StaticResource Locator}}"> <interactivity:Interaction.Triggers> <interactivity:EventTrigger EventName="Closing" > <command:EventToCommand Command="{Binding Path=OnClosingCommand}"/> </interactivity:EventTrigger> </interactivity:Interaction.Triggers> |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| public RelayCommand OnClosingCommand => _closingCommand ?? (_closingCommand = new RelayCommand(OnClosing));
private void OnClosing() { SimpleIoc.Default.Unregister<PersonViewModel>(); SimpleIoc.Default.Register<PersonViewModel>(); } |
Bei jedem schließen des Fensters wird das ViewModel entfernt und wieder neu-registriert. Es gibt Ansätze wo beim erzeugen im ViewModelLocator eine eindeutige ID dem jeweiligen ViewModel "mitgegeben" wird und anhand dieser ID genau diese Instanz wieder entfernt wird. Da ich mit sicherheit immer nur eine Instanz benötige galube ich das ich diesen Ansatz nicht verfolgen brauche. :?:
Ich hoffe ich konnte einigermaßen beschreiben um was es mir geht und hoffe das mir jemand den richtigen Weg zeigen kann.
Vielen Dank!
Yankyy02 - Di 05.09.17 21:27
Hey,
danke für deine Antwort. Ich habe mir den Thread im Link durchgelesen. Hier scheint es so als ob sein Problem meine Lösung wäre da er ja genau den umgekehrten Weg haben möchte und zwar immer eine Instanz des ViewModels in jeder neu erzeugten View was ja ohne hin der Fall ist außer man erzeugt mehrere Views(Windows).
Was ich nicht möchte ist das mischen mehrere Frameworks in einem Projekt zumindest was das MVVM Pattern angeht. Ich dachte es gäbe da Best Practice Wege um das umzusetzen. Ich suche noch ein bisschen den roten Faden, wenn du verstehst was ich meine.
Siehst du grundsätzlich ein Problem in der Umsetzung wie ich es aktuell habe? Was ich nicht rausfinden konnte ob beim entfernen und neu registrieren das ViewModel auch tatsächlich "zerstört" wird oder ob es noch irgendwo vorgehalten wird! :?:
LG
Yankyy02 - Mi 06.09.17 23:33
Vorerst sorry für die verspätete Rückmeldung .... dein Tip war glaub ich goldrichtig. Ich hätte mir den Source-Code eher ansehen sollen aber im Forum nachzufragen war natürlich gemütlicher. :oops:
In der Klasse SimpleIoc gibt es eine Methode die immer eine neue Instanz des benötigten ViewModels liefert ohne es zu cachen.
C#-Quelltext
1: 2: 3: 4:
| public object GetInstanceWithoutCaching(Type serviceType) { return DoGetService(serviceType, _defaultKey, false); } |
In der View habe ich nun das Unloaded Event aboniert und im ViewModel IDisposable implementiert. Dispose() wird dann aufgerufen wenn Unloaded feuert.
XML-Daten
1: 2: 3: 4: 5:
| <interactivity:Interaction.Triggers> <interactivity:EventTrigger EventName="Unloaded" > <command:EventToCommand Command="{Binding Path=OnClosingCommand}"/> </interactivity:EventTrigger> </interactivity:Interaction.Triggers> |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| public class PersonViewModel : ViewModelBase, IDisposable { private ObservableCollection<Person> _persons; private ListCollectionView _personsView; private RelayCommand _closingCommand; private bool _disposed = false;
public PersonViewModel() { _persons = new ObservableCollection<Person>(Data.LoadPersons()); _personsView = new ListCollectionView(_persons); }
public ListCollectionView Persons => _personsView;
public RelayCommand OnClosingCommand => _closingCommand ?? (_closingCommand = new RelayCommand(OnClosing));
private void OnClosing() { this.Dispose(true); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _persons = null; _personsView = null; }
_disposed = true; } }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
~PersonViewModel() { Dispose(false); }
} |
Nun sollten doch keine unnötigen Instanzen des ViewModels mehr herumschwieren sobald ich die View (Fenster) schließe und der GC aufräumt... :?:
Ich weis du hast eingangs erwähnt das du mit dem Toolkit noch nicht gearbeitet hast aber da du allerhand Erfahrung hast kannst du sicher besser einschätzen ob da noch irgendwelche Gefahren auf mich lauern.
LG
Yankyy02 - Do 07.09.17 23:30
Danke für deine Mühen die Links rauszusuchen die sind natürlich nützlich. Grundsätzlich würde ich sagen das ich das Disposable-Pattern verstanden habe. Das ViewModel so wie es hier ist ist natürlich nicht das produktive bzw. eines der Anwendung, sondern dient nur als Beispiel. In der Anwendung selbst kommt zusätzlich das Entity Framework zur Anwendung und da dachte ich wenn ich in den ViewModels IDisposable implementiere hier Dispose für den DBContext aufrufe und wer weiß was sonst noch so dazukommt. Mir geht es grundsätzlich darum das nicht unzählige ViewModels durch den Ioc im Speicher gehalten werden da es dadurch sicher früher oder später zu Fehlern kommen kann und beim laden der View immer die aktuellen Daten abgerufen werden und nicht der letzte Stand beim schließen des Fensters bzw. der View angezeigt wird. Genau dieses Vorgehen und eventuelle Fallstricke wird in keinem der Tutorials oder in der Doku beschrieben.
Durch den Aufruf von
C#-Quelltext
1:
| SimpleIoc.Default.GetInstanceWithoutCaching<PersonViewModel>(); |
wird mir nun immer eine neue Instanz des jeweiligen ViewModels erzeugt. Was mir jedoch sorgen macht ist (und nicht beschrieben ist) ob diese erzeugten Instanzen irgendwo von mir disposed werden müssen wenn die View geschlossen wird.
C#-Quelltext
1:
| public static void Cleanup(){} |
wird ja nur aufgerufen, wenn die Anwendung beendet wird um alle registrierten ViewModels und Ressourcen freizugeben zumindest habe ich das so verstanden.
LG
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!