2016-11-30 1 views
0

Ich benutze die Vorlage Modern UI for WPF in einer .NET 4.0-Anwendung, in der eine Seite einen asynchronen Befehl ausführen muss, bevor sie zu einer anderen Seite zurück navigiert. Zur gleichen Zeit muss der UI-Thread während der Ausführung des Befehls entsperrt werden. Wenn ich dies tun:Führe einen Async-Befehl aus, bevor du zurück navigierst

public void OnNavigatingFrom(FirstFloor.ModernUI.Windows.Navigation.NavigatingCancelEventArgs e) 
    { 
     TaskEx.Run(() => 
      { 
       //Replace Sleep call by the async command execution 
       System.Threading.Thread.Sleep(5000); 
      }).Wait();} 

Die OnNavigatingFrom wartet, bevor die Navigation zurück, aber die UI wird während dieser Zeit gesperrt.

Haben Sie Ideen, wie Sie den asynchronen Code in einem anderen Kontext ausführen und OnNavigatingFrom "synchron" ausführen?

EDIT: Es gibt eine similar thread mit einem Workaround und keine schlüssige Antwort.

+1

Sie wissen, Warten ist ein blockierender Anruf? –

+0

Ich mache und ich weiß, das ist ein Problem. Wie kann ich es nicht blockierend machen, wenn man bedenkt, dass die aufrufende Methode (OnNavigatingFrom) erst nach Abschluss des Vorgangs zurückkehren kann? –

+0

Wenn * (und nur wenn) * die 'OnNavigatingFrom'-Methode ein Event-Handler ist, können Sie es als 'public async void' setzen (Danke, dass Sie viel Literatur von Stephen Cleary gelesen haben). Damit können Sie 'erwarten' verwenden. Z.B. 'erwarten DoSomethingAsync();'. Die aufrufende Methode wird nicht zurückgeben, bis die erwartete Aufgabe abgeschlossen ist –

Antwort

1

eine Seite braucht ein asynchrones Komma auszuführen nd bevor es zurück zu einer anderen Seite navigiert

Dies ist das Problem. Benutzeroberflächen sind nicht asynchron, Punkt. Sie können einen asynchronen Vorgang nicht einfach in den Mix stecken, während die Benutzeroberfläche einen Übergang ausführt.

Denken Sie darüber nach: als Benutzer, wenn Sie sich entscheiden, zurück zu navigieren, und es gibt einen Netzwerk-Schluckauf oder etwas und das Programm friert für ein paar Sekunden beim Navigieren zurück, das ist eine schlechte Benutzererfahrung, richtig? Die UI kann einfach nicht auf asynchrone Arbeit während eines Updates warten.

Was können Sie tun, um die Arbeit zu tun vor der Benutzer erlaubt ist, zurück zu navigieren. Sie können beispielsweise die Absicht des Benutzers erfassen, während der Ausführung der Operation zurück zu navigieren und eine Art "Bitte warten" -UI anzuzeigen, und dann nach Abschluss der Operation die tatsächliche Navigation ausführen.

+0

Was Sie vorschlagen, ist was ich tue. Das Problem ist, dass diese "zurück navigieren" -Methode (OnNavigatingFrom), die meine Seite ausführt, nicht auf asynchrone Operationen wartet, wo die "Bitte warten" -UI während des Betriebs angezeigt wird. Am Ende mache ich die Navigation ab, mache meine Async-Sachen und navigiere dann von meinem ViewModel zurück, wenn der Vorgang abgeschlossen ist. –

+0

@IgorKondrasovas: Ja, das musst du tun. 'OnNavigatingFrom' * kann nicht * warten - es sollte nicht warten - es macht keinen Sinn zu versuchen, es warten zu lassen. –

0

Nur await die Task anstelle von .Wait().

Siehe Using async-await on .net 4, wie in .NET 4.0

+0

warten die Aufgabe nicht funktioniert, weil die aufrufende Methode nicht auf die Beendigung warten wird, bevor Sie zurück navigieren. –

+1

Die Verwendung von await bedeutet, dass die Ereignisbehandlungsroutine nicht zurückkehrt, bis die erwartete Aufgabe abgeschlossen ist. Die UI kann jedoch weiterarbeiten. Wenn Sie Wait() (oder einen anderen Blockierungsmechanismus) verwenden, wird die Benutzeroberfläche blockiert. Du kannst es nicht auf beide Arten haben. Vielleicht können Sie nach Ablauf der Wartezeit eine Markierung setzen, die anderen Code im UI-Thread erkennt? – sellotape

+0

Kannst du nicht einfach tun, was du tun willst, nachdem die Wartezeit im Event-Handler abgelaufen ist? – sellotape

2

hier zu erwarten ist, was Sie tun müssen:

public void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    // Fire and forget. 
    Task.Run(() => MyCommandAsync()); 
} 

Die oben ist ein Feuer und Ansatz vergessen, stattdessen ist es bevorzugt, async zu verwenden und await:

public async void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    await MyCommandAsync(); 
} 
+1

Dies funktioniert nicht, da OnNavigatingFrom ein Event-Handler ist und das Hinzufügen des Async im Methodenkopf keinen Unterschied macht. Die Seite wird sofort zurück navigieren. –

+1

@IgorKondrasovas, das ist eine Frage der Verwendung des richtigen Ereignisses. '' Erwarten '' ist der richtige Weg, um auf einen asynchronen Vorgang zu warten. Sie verwenden einfach das falsche Ereignis/Muster. Anstatt * zu navigieren *, sollten Sie einen Befehl verwenden, der nach Fertigstellung auf die neue Seite navigiert. –

+0

Das erste Formular wird sofort die Ausführung von 'MyCommandAsync' in den Thread-Pool posten und zurückgeben, während der zweite auf dem UI-Thread ausgeführt wird die erste unvollständige wartezeit. –

0

Verwenden Sie OnNavigatingFrom, um Ihre Sachen zu tun. e.Cancel zurückgehen. Verwenden Sie Frame.GoBack(), nachdem Ihre Operation abgeschlossen ist.

protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e) 
{ 
    if (Current.HasModifications()) 
    { 
     e.Cancel = true; 
     await Current.Save().ContinueWith((t) => 
     { 
      //Go Back after the Operation has finished 
      Frame.GoBack(); 
     }, TaskScheduler.FromCurrentSynchronizationContext()); 
    } 
    else 
    { 
     base.OnNavigatingFrom(e); 
    } 
} 
Verwandte Themen