7

Ich habe ein View-Modell mit einem Konstruktor, der einen Service benötigt. Ich benutze GalaSoft MvvmLight, die einen Service-Locator verwendet, um die Ansicht mit dem Ansichtsmodell zu verbinden.MVVM View-Modell und asynchrone Dateninitialisierung

SimpleIOC übernimmt die Bereitstellung des Dienstes für den Viewmodels-Konstruktor, aber ich muss mein Viewmodel irgendwie mit Daten aus einer Datenquelle füllen. Mein Ansichtsmodell sieht wie folgt aus: -

public class MainPageViewModel : ViewModelBase 
{ 
    private readonly GroupService _groupService; 
    private readonly GroupFactory _groupFactory; 
    private readonly ObservableCollection<GroupVM> _groupVms = new ObservableCollection<GroupVM>(); 


    public MainPageViewModel(Domain.Services.GroupService groupService, VMFactories.GroupFactory groupFactory) 
    { 
     _groupService = groupService; 
     _groupFactory = groupFactory; 
    } 

    public async Task Init() 
    { 
     var groups = await _groupService.LoadGroups(); 
     foreach (var group in groups) 
     { 
      GroupVms.Add(_groupFactory.Create(group)); 
     } 
    } 

    public ObservableCollection<GroupVM> GroupVms { get { return _groupVms; } } 
} 

Irgendwie ist der init-Methode muss ein abgewartet werden genannt, aber ich weiß nicht, wie man am besten, dies zu tun? Ich kann mich drei Möglichkeiten: -

  1. Ich nenne Init nur auf dem Konstruktor, aber es nicht zu erwarten (ich weiß, das ist wirklich schlechte Praxis)
  2. Ich nenne Init auf ViewModelLocator Objekt, aber da kann ich nicht zurückgeben eine Aufgabe Ich kann nicht wieder auf die init warten
  3. Auf die Auslastung der Ansicht ich den DataContext auf eine Art von IAsyncViewmodel und warten auf die Init-Methode.

Ich habe Option 3 in einem früheren Windows 8 Store-Projekt verwendet, aber es fühlt sich einfach falsch an. Jeder Rat würde wirklich geschätzt werden!

Dank

Ross

Antwort

7

Ich bin neugierig, warum Sie einen asynchronen Anruf nicht für eine schlechte Praxis halten. Meiner Meinung nach ist es nicht schlimm, solange Sie wissen, was das bedeutet, dass der Anruf im Hintergrund ausgeführt wird und jederzeit zurückkommt.

In der Regel, was ich tue ist, dass ich die asynchrone Methode im Konstruktor für Design-Zeit Datenerstellungszweck aufrufen und ich erwarte es nicht. Ich kümmere mich nur darum, die PropertyChanged und CollectionChanged Ereignisse anzuheben, wo die Bindungen aktualisiert werden müssen, und das macht den Trick.

Prost Laurent

+0

Guter Punkt, es war mehr "eines dieser Dinge", die ich übernommen hatte, aber nicht wirklich darüber nachgedacht hatte. Hier ein paar mehr Informationen über: http://stackoverflow.com/questions/7261173/c-sharp-start-async-method-within-object-constructor-bad-practice Grundsätzlich ist es, weil, wenn das Objekt konstruiert ist, es immer noch ist. Dinge tun "vielleicht unerwartet, und es ist sehr schwierig, Ausnahmen zu behandeln, die auftreten könnten. Ich habe beide Möglichkeiten ausprobiert, und ich denke, ich bevorzuge die Init im Konstruktor, aber immer noch nicht sicher! –

+0

Tipp: Um die "Squigglies" in Visual Studio zu vermeiden, weisen Sie den Wert des zurückgegebenen Tasks einer Dummy-Variablen zu –

1

Ich bin nicht so vertraut mit MvvmLight wie ich einmal war, aber ich habe in einer Vielzahl von Möglichkeiten mit async Konstrukteure zu beschäftigen versucht.

Option (1) hat Fehlerbehandlung Komplexität. Option (3) zwingt InitAsync, zugänglich zu sein.

Ich ziehe einen async Fabrik Ansatz (zum Beispiel Option (2), wo die DataContext würde null bleiben, bis die Initialisierung abgeschlossen VM), aber es klingt wie ViewModelLocator nicht dafür arbeiten. Also (für jetzt) ​​müssen Sie zwischen einer async Fabrik wählen, die IoC nicht benutzt und einer der anderen Optionen (1 oder 3), die nicht ideal sind.

Persönlich würde ich IoC für VM/View-Bindung (ich verwende nie IoC für diese sowieso; meine Ansichten hängen von meinen VMs) und verwenden Sie eine async Factory-Methode. Die anderen Optionen sind jedoch ideal, wenn Sie bei IoC bleiben möchten. Für VMs wäre Option (1) etwas besser als Option (3), wenn Sie in Ihrer InitAsync Methode immer eine try/catch Top-Level-Methode hätten.

+0

Danke, werde ich die Frage offen für ein bisschen mehr verlassen, wie ich andere Völker Meinungen dazu hören, würde gerne. –