2016-07-28 47 views
3

Ich habe ein Sequencing-Problem in meinem ViewModel, das scheint Thread-bezogen zu sein, aber ich kann nicht recht abschätzen, was falsch läuft oder wie mein "Fix" es behebt.MvvmCross ShowViewModel Ladesequenz

Ich habe ein ViewModel, das eine asynchrone Methode aufrufen muss, um seine ursprünglichen Daten zu laden. Ich rufe die async-Methode von der Init-Methode auf, die MvvmCross automatisch aufruft. Wenn das Laden aus irgendeinem Grund fehlschlägt, möchte ich einen Fehlerbildschirm anzeigen, aber das Aufrufen von ShowViewModel innerhalb der von Init aufgerufenen Methode führt nicht zum erwarteten Ergebnis. ShowViewModel wird korrekt aufgerufen, aber wenn Sie dies im Debugger verfolgen, wird das ErrorViewModel angezeigt, bevor das ursprüngliche ViewModel/View geladen wurde. Es wird also geladen, aber nicht angezeigt, da es vom ursprünglichen ViewModel überschrieben wird.

Hier ist eine vereinfachte Version des Ladecode:

public async Task Init() 
{ 
    await LoadInitialDataAsync(); 
} 

protected async Task LoadInitialDataAsync() 
{ 
    var loadResult = await LoadSomeStuffAsync(); 
    if (loadResult.IsBadNews) 
    { 
     ShowViewModel<ErrorViewModel>(); 
     return; 
    } 
} 

Die MvxTrace logs sagen mir, dass ShowViewModel auf ErrorViewModel sofort aufgerufen wird, nachdem es auf dem ursprünglichen Ansichtsmodell genannt wird, aber nur die erste Ansicht zeigt, nicht die ErrorView.

Um "zu beheben" kann ich eine von zwei Dingen tun.

Ich kann den Anruf zu LoadInitialDataAsync in Task.Run wickeln:

await Task.Run(async() => 
{ 
    await LoadInitialDataAsync(); 
}); 

Oder ich eine kleine Verzögerung vor dem inneren ShowViewModel Anruf hinzufügen:

protected async Task LoadInitialDataAsync() 
{ 
    var loadResult = await LoadSomeStuffAsync(); 
    if (loadResult.IsBadNews) 
    { 
     await Task.Delay(1); 
     ShowViewModel<ErrorViewModel>(); 
     return; 
    } 
} 

Jede dieser Änderungen erzeugt die gewünschtes Ergebnis - wenn während des Ladens ein Bad Thing auftritt, zeigt das ErrorViewModel seine Ansicht an.

Das Problem ist, ich traue diesem Fix nicht, weil ich nicht verstehe, was unter der sprichwörtlichen Haube schief läuft, und deshalb nicht weiß, wie robust dieser Fix ist. Es scheint ein willkürliches Timing-Ding zu sein, das irgendwann in der Zukunft zur unpassendsten Zeit wieder brechen wird.

Wenn jemand die MvvmCross Interna gut genug versteht, um damit zu helfen, würde ich es schätzen!

+0

Könnten Sie vielleicht ein Repo/Sample bereitstellen, das dieses Problem reproduziert? Wenn Sie Ihre vereinfachte Version oben verwenden, scheint dieses Problem nicht zu auftreten. – Plac3Hold3r

+0

Ich habe das gleiche Problem, das niemand auf den "Antworten" zu verstehen scheint. Das Problem ist, dass Sie in Ihrem CORE-Projekt einige Aufgaben haben, auf die Sie warten müssen, und während dieser Wartezeit einen "Loader" anzeigen möchten. Recht? Hast du eine Lösung dafür gefunden? – Ph0b0x

Antwort

3

Die Init Methode sollte sehr wenig tun. Init wird normalerweise verwendet, um einige Navigationsparameter zu kopieren, die an ShowViewModel<TViewModel>() übergeben wurden. Die Start Methode ist, wo Sie ViewModel-Start wie Aufruf von LoadInitialDataAsync ausführen sollen. Bitte überprüfen Sie die App Lifecycle documentation für weitere Informationen.

+0

Vielen Dank, die Dokumentation ist hilfreich. Ich habe jedoch versucht, Start() anstelle von Init() und das Verhalten ist genau das gleiche. –

0

Basierend auf https://github.com/MvvmCross/MvvmCross/wiki/viewmodel--to-viewmodel-navigation:

Wenn Ihre App eine Ansichtsmodell Seite angezeigt wird, sagen FirstViewModel, dann dass erste Seite anfordern kann, dass das Display nach vorne in eine neue Ansichtsmodell Seite bewegt wird, sagen SecondViewModel durch die Verwendung ein Aufruf wie:

ShowViewModel<SecondViewModel>(); 

Wenn die FirstViewModel macht diese Anforderung, dann wird der MvvmCross Rahmen:

  • einen liegen als ‚Seite‘ verwenden für SecondViewModel innerhalb der App - in der Regel wird dies
  • Erstellen Sie eine neue Instanz dieser SecondView
  • Erstellen einer SecondViewModel und bieten es als Datacontext für die neue SecondView sein SecondView
  • stellen Sie das Betriebssystem, um die SecondView anzuzeigen

die ShowViewModel<ErrorViewModel() für Sie aufgerufen wird, während die ursprüngliche Ansicht nicht noch gezeigt, die das iss sein könnte dafür und würde zu Ihrem Debugger-Verhalten passen.

Die Verzögerung gibt es wahrscheinlich genug Zeit zu zeigen und die asynchrone Aufgabe blockiert es nicht, so dass es zeigt, dann ist die Anzeige beendet und es wechselt auf die andere Ansicht.

Eine Option wäre wahrscheinlich die Initialisierung vor und übergeben Sie die Daten mit dem ShowViewModel, obwohl ich keine Erfahrung damit habe. Oder speichern Sie den Fehlerstatus, lassen Sie die Ansicht laden und rufen Sie das Ansichtsmodell aus der Ansicht auf, um es nach dem Erstellen wechseln zu lassen.

Obwohl ich nicht wirklich Fan von beiden, das ist, warum ich meine Initialisierung über Dienste vor und wenn es fehlschlägt reagieren vor dem Wechsel auf die neue Viewmodel.

Weiß nicht, wie komplex Ihre aktuelle Struktur ist und was am besten funktioniert.