如何在视图模型中异步任务后更新UI
本文关键字:任务 更新 UI 异步 视图 模型 | 更新日期: 2023-09-27 17:59:31
在我的Xamarin.Forms
pcl项目中,我有一个包含label
的xaml
页面。我想在一些async task
之后更新label
。在我的ViewModel constructor
中,我为label
设置了默认文本。并创建一个名为SomeTask()
的async Task
函数。
问题1:在哪里可以调用SomeTask()
函数。无法在constructor
中调用async Task
函数。
问题2:如何在async Task SomeTask()
函数后更新Label
文本。
我的代码:
public class MyPageViewModel : ViewModelBase
{
private String _selectedText;
public String SelectedText
{
get { return _selectedText; }
set {
if (_selectedText != value)
{
_selectedText = value;
}
}
}
public MyPageViewModel ()
{
_selectedText = "Welcome"; //Default text
}
private async Task<string> SomeTask()
{
return await Task.Run(async () =>
{
await Task.Delay(3000); //Dummy task. It will return the status of Task.
return "Thanks"; //Update Text
});
}
}
我建议您使用我的NotifyTask
类型;在我的MSDN文章中介绍了异步MVVM数据绑定,我认为这是最简单的方法:
public class MyPageViewModel : ViewModelBase
{
private NotifyTask<string> _selectedText;
public NotifyTask<string> SelectedText => _selectedText;
public MyPageViewModel()
{
_selectedText = NotifyTask.Create(SomeTask(), "Welcome");
}
private async Task<string> SomeTask()
{
await Task.Delay(3000);
return "Thanks";
}
}
然后,您的数据绑定将更改为绑定到SelectedText.Result
,以显示"欢迎",然后显示"谢谢"。数据绑定还有其他NotifyTask<T>
属性,如IsNotCompleted
、IsCompleted
和ErrorMessage
,它们还允许您通过数据绑定处理故障情况。
如果你不想使用这种类型,你可以自己做一些类似的事情:
public class MyPageViewModel : ViewModelBase
{
private string _selectedText;
public string SelectedText
{
get { return _selectedText; }
set
{
if (_selectedText != value)
{
_selectedText = value;
RaisePropertyNotifyChanged(); // However you're doing this.
}
}
}
public MyPageViewModel()
{
_selectedText = "Welcome";
var _ = RunSomeTask();
}
private async Task RunSomeTask()
{
try
{
SelectedText = await SomeTask();
}
catch (Exception ex)
{
// TODO: Handle the exception.
// It *must* be handled here, or else it will be silently ignored!
}
}
private async Task<string> SomeTask()
{
await Task.Delay(3000);
return "Thanks";
}
}
构造函数启动RunSomeTask
操作,然后显式忽略其结果(注意,这意味着将忽略所有异常)。RunSomeTask
负责运行SomeTask
并处理其结果(以及异常)。结果仅用于更新SelectedText
,并且将根据您认为适合您的应用程序的方式处理异常。
怎么样
public MyPageViewModel()
{
_selectedText = "Welcome"; //Default text
SomeTask().ContinueWith(previousTask => SelectedText = previousTask.Result);
}
您可以创建一个异步工厂方法并使构造函数私有。然后调用该方法来创建MyPageViewModel
的实例。在该方法中,您可以调用string str = await SomeTask
public class MyPageViewModel : ViewModelBase
{
public async MyPageViewModel CreateAsync()
{
var model = new MyPageViewModel();
SelectedText = await SomeTask();
return model;
}
private MyPageViewModel ()
{
_selectedText = "Welcome"; //Default text
}
private Task<string> SomeTask()
{
return Task.Run(async () =>
{
await Task.Delay(3000); //Dummy task. It will return the status of Task.
return "Thanks"; //Update Text
});
}
}
因此,与其像这样创建模型:
var model = new MyPageViewModel();
你这样创建它:
var model = await MyPageViewModel.CreateAsync();
问题1:
使用委托和事件。
-
创建委派&关联事件:
private delegate void MyDelegate();
private event MyDelegate myEvent;
-
订阅构造函数中的事件:
myEvent += async () => await SomeTask();
-
在任何需要的地方执行事件:
myEvent(); //Note: Check the event for null, before executing
问题2:
如果在非UI线程上,则:
-
使用一些框架类来执行UI操作:例如-Xamarin提供Device.BeginVokeOnMainThread
-
我们可能总是将DataBinding与Label一起使用,并且只使用事件订阅来更新ViewModel中Binding Path的值。
string _message;
public string Message
{
get => _message;
set
{
_message = value;
}
}
myEvent += () => Message = "New Value";
<Label Text = "{Binding Message}"/>