bro*_*and 3 c# multithreading ui-thread xamarin xamarin.forms
很简单的例子:
<StackLayout>
<Button Text="{Binding LoginButtonText}" Clicked="Button_Clicked"></Button>
</StackLayout>
Run Code Online (Sandbox Code Playgroud)
代码背后:
public partial class ItemsPage : ContentPage
{
private ViewModels.ItemsViewModel _viewModel;
public ItemsPage()
{
_viewModel = new ItemsViewModel();
BindingContext = _viewModel;
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
this._viewModel.LoginButtonText = "Start" + DateTime.Now.ToString();
// this loop is just for testing purposes. To demonstrate
// that this loop block UI thread
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 1000; j++)
{
string s = new Random(45).NextDouble().ToString();
}
}
this._viewModel.LoginButtonText = "End " + DateTime.Now.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用MVVM - INotifyPropertyChanged
public class ItemsViewModel : ObservableObject
{
private string _loginButtonText;
public string LoginButtonText
{
get { return _loginButtonText; }
set { SetProperty(ref _loginButtonText, value); }
}
}
Run Code Online (Sandbox Code Playgroud)
ObservableObject实现可以在这里看到:https://codeshare.io/G87N74
当我点击该按钮几秒钟(4或5)按钮上的文字获取价值"结束2017年3月8日8点55分33秒"后(将它取决于课程的当前时间戳).按钮文本Start + DateTime不会出现.
如果我写这个:
private void Button_Clicked(object sender, EventArgs e)
{
this._viewModel.LoginButtonText= "Start" + DateTime.Now.ToString();
// I assume here execution switches threads as it sees Task as a new thread. While waiting for task to finish
// it finished mvvm INotifyPropertyChanged change.Invoke call and updates the button text
await Task.Delay(5000);
this._viewModel.LoginButtonText = "End " + DateTime.Now.ToString();
}
Run Code Online (Sandbox Code Playgroud)
但它不是100%,因为我们不知道线程将如何安排执行.当我们点击事件方法时,是否有一种简单的方法可以立即更新UI?
有一个方法,Device.BeginInvokeOnMainThread()但它返回void,因此它不会阻止UI.
我们无法立即从后台线程对UI进行更改.来自后台线程的UI线程上的所有操作将在下一个UI线程循环中执行.如果您的应用程序没有被某些密集型任务阻止,它将尽可能地立即接近我们.
如果你想让你的第一个例子运作良好,那就把那些繁重的操作放到backgorund任务中:
this._viewModel.LoginButtonText = "Start" + DateTime.Now.ToString();
//With await Task.Run (creating new thread) on heavy operation this thread is not blocked
//so previous operation is scheduled to UI thread and changes will appear on screen
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 1000; j++)
{
string s = new Random(45).NextDouble().ToString();
}
}
});
this._viewModel.LoginButtonText = "End " + DateTime.Now.ToString();
Run Code Online (Sandbox Code Playgroud)
这里还有来自Xamarin关于线程的文档:
应用程序用户界面始终是单线程的,即使在多线程设备中 - 只有一种屏幕表示,所显示的内容的任何更改都需要通过单个"访问点"进行协调.这可以防止多个线程同时尝试更新同一个像素(例如)!