2016-11-10 83 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"; 
     });