2016-11-10 4 views
4

Ich verwende Xamarin Forms, um eine Cross-Platform-App zu entwickeln.Xamarin Forms ändern Text der Schaltfläche während der Wartezeit

Ich möchte den Text der Schaltfläche "Do Something" in etwas wie "Wait" ändern, während der Code die Routine verarbeitet, und zurück zu "Do Something", nachdem der Code zu Ende ausgeführt wurde.

Das Problem ist: Die Schaltfläche Text ändert sich nur, nachdem der Code abgeschlossen ist.

Einfache Exemple:

private void Button_Clicked(object sender, EventArgs e) 
{ 
    var btn = (Button)sender; 
    btn.Text = "Wait"; 

    ...some code.. 

    btn.Text = "Do Something"; 
} 

Es gibt eine Möglichkeit, zu "zwingen", das Update von Text zu "Wait" vor dem Code Finish?

+0

Der UI-Thread, indem Sie Ihre Codeausführung blockiert wird. Sie müssen den Button-Text in einem separaten Thread ändern –

+0

Vielen Dank für die Info Sandeep! –

Antwort

1
private async void Btn1_Clicked(object sender, EventArgs e) 
    { 
     btn1.Text = "Wait"; 

     await Task.Run(async() => 
     { 
      for (int i = 1; i <= 5; i++) 
      { 
       //if your code requires UI then wrap it in BeginInvokeOnMainThread 
       //otherwise just run your code 
       Device.BeginInvokeOnMainThread(() => 
       { 
        btn1.Text = $"Wait {i}"; 
       }); 
       await Task.Delay(1000); 
      } 
     }); 

     btn1.Text = "Done"; 


    } 
+0

Vielen Dank Yuri! Mit ein paar Anpassungen funktioniert perfekt! –

+0

'btn1.Text =" Wait ";' geschieht erst, wenn die Methode 'Btn1_Clicked' beendet ist/zu Ende geht. Ich bin gespannt, welcher Thread ausgeführt wird, wenn die Methode 'Btn1_Clicked' ausgeführt wird? – broadband

+0

Gibt es eine Möglichkeit, Button-Text zu aktualisieren, während wir in der 'Btn1_clicked' Methode sind. 'Device.BeginInvokeOnMainThread' gibt void zurück, so dass wir nicht darauf warten können (warten). – broadband

2

Der Hauptpunkt ist, dass Sie die asynchronen Operationen haben möchten, auf die Sie warten müssen, damit sie nicht auf dem UI-Thread passieren. Die Lösung von Yuri macht das, aber Sie können auch Ihre asynchronen Operationen ausführen und dann, wenn Sie Aktualisierungen an der Benutzeroberfläche vornehmen müssen, müssen Sie diese nur auf dem UI-Thread ausführen, um zu verhindern, dass die Benutzeroberfläche gesperrt wird.

Das eigentliche Problem kommt davon, wie Ihre Threads arbeiten. Wenn Sie diese Echtzeit sehen möchten, öffnen Sie das Threads-Debug-Pad in Xamarin Stud und beobachten Sie die Threads, während Sie den Code durchgehen.

Lassen Sie uns Ihren Code als Beispiel:

private void Button_Clicked(object sender, EventArgs e) 
{ 
    var btn = (Button)sender; 
    btn.Text = "Wait"; 
    ... 

Als wir die "Button_Clicked" Event-Handler geben, sind wir nun auf dem UI-Thread. Woher wissen wir? weil der Benutzer auf den Button geklickt hat und wir hier sind. Alles wurde im Hauptthread der Benutzeroberfläche ausgeführt. Was auch immer wir als nächstes in unserem Code tun, wird weiterhin auf diesem Thread laufen, wenn das Betriebssystem nicht bestimmt, dass es die Threads aus irgendeinem Grund verwalten muss (Leistung, so funktioniert das OS usw.).

Wenn Ihr Code eine asynchrone Aufgabe ausführt, wie das Senden eines Webanforderungsaufrufs, um Daten aus einer REST-API abzurufen, müssen Sie sich bewusst sein, auf welchem ​​Thread Sie sich befinden. Wir können nicht garantieren, dass unser Webanforderungsaufruf auf dem UI-Thread oder einem Thread ohne manuelle Bearbeitung ausgeführt wird. Das ist der Vorteil unserer fortschrittlichen Betriebssysteme, die für uns die Mehrkern-Multi-Thread-Bearbeitung übernehmen.

Aus diesem Grund möchten wir sicherstellen, dass alle Aktualisierungen der Benutzeroberfläche auf dem UI-Thread geschehen. Die richtige Lösung für Ihren Code würde unten sein:

private async void Btn1_Clicked(object sender, EventArgs e) 
{ 
    var btn = (Button)sender; 
    btn.Text = "Wait"; 

    ...some code...maybe async or not (take out async above if not) 

    Device.BeginInvokeOnMainThread(() => 
    { 
     btn.Text = "Do Something"; 
    }); 
}  

Dies funktioniert für uns, weil wir Xamarin.Forms sagen, dass Befehl auf dem Haupt-Thread ausgeführt werden. Xamarin.Forms macht den Haupt-UI-Thread auf diese Weise verfügbar. Eine andere Möglichkeit wäre, den Kontext unseres UI-Threads zu nehmen und zwischenzuspeichern, um ihn bei Aktualisierungen zu verwenden. Dies wird normalerweise in Xamarin.Android- und Xamarin.iOS-Anwendungen ausgeführt.

Der eigentliche Weg, all dies zu tun, ist durch Datenbindungen. Xamarin.Forms wurde mit der Absicht erstellt, mit einem Model-View-ViewModel (MVVM) -Muster verwendet zu werden. Xamarin.Forms Bindings behandelt alle Kontextwechsel für Sie, wenn Sie OnPropertyChanged aufrufen. Auf diese Weise können Sie einfach die Eigenschaft in Ihrem ViewModel aktualisieren, die an den Text Ihrer Schaltflächen gebunden ist.

Ich hoffe, dies hilft ein besseres Verständnis von dem, was auf der Thread-Ebene passiert!

Disclosure: Ich arbeite für Xamarin/Microsoft

+1

Ich möchte hier keine Diskussion erstellen, aber ... 1. "Einige Code ..." kann Synchronisierungsvorgänge durchführen und deshalb wurde diese Frage gepostet. 2. In Ihrem Beispiel ist es nicht sinnvoll, btn.Text = "Do Something" zu umbrechen; in BeginInvokeOnMainThread. In Btn1_Clicked können Sie einfach Text wie oben für "Warten" einstellen. 3. Sie haben in meinem Beispiel gesagt, dass alles auf dem UI-Thread funktioniert. Sehen Sie sich Task.Run an. Es heißt, weil ich "etwas Code ..." async gemacht habe. Arbeiten Sie wirklich für Xamarin? Ich bezweifle ehrlich. –

+1

Und warum haben Sie Ihren Button-Handler asynchron gemacht? Ich sehe keine erwarten. Sie gehen davon aus, dass "irgendein Code" asynchron ist. Was ist, wenn es nicht ist? –

+0

@YuriS Ich versuche nicht, mit dir darüber zu sprechen. Ich habe meine Antwort so bearbeitet, dass sie in Ihre Kommentare passt. Erledigt. – BrewMate

0

In Xamarin.forms verwenden diese Weise

Device.BeginInvokeOnMainThread(() => 
     { 
     Task.Delay(4000).Wait(); 
      btn.Text = "Do Something"; 
     }); 
Verwandte Themen