如何在viewmodel中的异步任务后更新UI
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在viewmodel中的异步任务后更新UI相关的知识,希望对你有一定的参考价值。
在我的Xamarin.Forms
pcl项目中,我有一个xaml
页面与label
。我想在一些label
之后更新async task
。在我的ViewModel constructor
中,我为我的label
设置了默认文本。并创建一个名为async Task
的SomeTask()
函数。
问题1:我在哪里可以调用SomeTask()
函数。无法在async Task
中调用constructor
函数。
问题2:如何在Label
函数后更新async Task SomeTask()
文本。
我的代码:
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
});
}
}
我建议你使用my NotifyTask
type;它在我的MSDN article on asynchronous MVVM data binding中描述,我认为这是最简单的方法:
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);
}
什么是someTask
?即,应该从哪里调用?出于什么原因?这里需要上下文来了解调用函数可以接受的内容。该功能应该在页面的负载上运行吗?它可以晚点运行吗?如何通过用户输入调用?
我建议你可以调用一个静态方法,例如:
public static async Task<T> someTask() {
Console.WriteLine("Asynchronous method called.");
}
然后,您可以从许多地方拨打此电话。这严格取决于需要调用方法的位置/时间。它可以在Load
事件处理程序中,以及其他地方。
您可以创建异步工厂方法并使构造函数为私有。然后,您调用该方法来创建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.BeginInvokeOnMainThread
- 我们可能总是将DataBinding与Label一起使用,并且仅使用事件订阅更新ViewModel中的Binding Path的值。
string _message;
public string Message
{
get => _message;
set
{
_message = value;
}
}
myEvent += () => Message = "New Value";
<Label Text = "{Binding Message}"/>
以上是关于如何在viewmodel中的异步任务后更新UI的主要内容,如果未能解决你的问题,请参考以下文章
如何在运行任务后或在任务运行期间更新 Asp .Net 中的 UI?
Android 异步更新UI-线程池-Future-Handler实例分析
Kendo UI:在 TextBox 中的 KeyPress 上强制更新 ViewModel
为啥将 ViewModel 添加到我的 SwiftUI 应用程序后我的 UI 没有更新?