2016-11-10 61 views
4

我使用Xamarin Forms來開發跨平臺應用程序。Xamarin表單在等待時更改按鈕的文本

我想在代碼處理例程時將「Do Something」按鈕的文本更改爲類似「Wait」的內容,並在代碼完成運行後返回到「Do Something」。

問題是:代碼完成後,按鈕文本纔會更改。

簡單例:

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

    ...some code.. 

    btn.Text = "Do Something"; 
} 

有一些方法來「逼」文本代碼完成之前,「等待」的更新?

+0

UI線程被阻塞你的代碼執行。您需要修改單獨線程中的Button文本 –

+0

感謝您的信息Sandeep! –

回答

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

非常感謝Yuri!經過一些調整,完美的作品! –

+0

'btn1.Text =「等待」;'直到'Btn1_Clicked'方法完成/結束纔會發生。我很好奇當'Btn1_Clicked'方法執行時線程正在運行嗎? – broadband

+0

有沒有辦法在'Btn1_clicked'方法中更新按鈕文本。 'Device.BeginInvokeOnMainThread'返回void,所以我們不能等待它(等待)。 – broadband

2

重點是你想要異步操作,你需要等待不會發生在UI線程。尤里的解決方案是這樣做的,但是你也可以做你的異步操作,然後如果你需要對UI進行任何更新,你只需要在UI線程上發生,以防止UI被鎖定。

真正的問題來自您的線程如何工作。如果你想看到這個實時,請拉開Xamarin Stud中的線程調試板,並在你逐步執行代碼時觀察線程。

讓我們把你的代碼爲例:

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

當我們進入「Button_Clicked」事件處理程序,我們現在都在UI線程。我們怎麼知道?因爲用戶點擊了按鈕,我們在這裏。一切都在主UI線程上運行。無論我們下一步在代碼中做什麼,都會繼續在該線程上運行,除非操作系統確定需要管理線程(性能,操作系統的工作原理等)。

如果您的某些代碼執行一些異步任務,例如發送Web請求調用以從REST API獲取某些數據,則需要了解您所在的線程。我們無法保證我們的網絡請求調用將在UI線程或任何線程上運行,而無需手動處理。這是我們高級操作系統的優勢,它爲我們處理了多核多線程處理。

因此,我們希望確保在UI線程上發生UI的任何更新。正確的解決方案,你的代碼將低於:

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"; 
    }); 
}  

這適用於我們,因爲我們告訴Xamarin.Forms到主線程中運行該命令。 Xamarin.Forms以這種方式公開主UI-Thread。另一種選擇是採用UI-Thread的上下文,並在進行更新時緩存它。這通常在Xamarin.Android和Xamarin.iOS應用程序中完成。

完成這一切的真正方法是通過數據綁定。 Xamarin.Forms是爲了與Model-View-ViewModel(MVVM)模式一起使用而構建的。當您撥打OnPropertyChanged時,Xamarin.Forms綁定會爲您處理所有上下文切換。這樣你就可以更新綁定到你的按鈕文本的ViewModel中的屬性。

我希望這可以幫助您更好地理解線程級別正在發生的事情!

披露:我對Xamarin /微軟工作

+1

我不想在這裏創建一個討論,但... 1.「一些代碼...」可以做同步操作,這就是爲什麼這個問題發佈。 2.在你的例子中,沒有必要包裝btn.Text =「做某事」;在BeginInvokeOnMainThread中。在Btn1_Clicked中,您可以像上面「等待」一樣設置文本。你在我的例子中說在UI線程中一切正常。錯誤。看看Task.Run。它被稱爲是因爲我使「某些代碼...」成爲異步。你真的爲Xamarin工作嗎?我真的懷疑。 –

+1

爲什麼你做你的按鈕處理程序異步?我沒有看到任何等待。你假設「一些代碼」是異步的。如果不是? –

+0

@YuriS我不想和你一起進入這個領域。我編輯了我的回覆以符合您的意見。完成。 – BrewMate

0

在Xamarin.forms用這種方式

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