我想知道是否有更好的方法将异步数据加载到属性中。 现在我创建一个异步函数并在属性的 Get 部分中引发一个任务,如下所示:
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get
{
if (prope == null)
{
Task.Run(()=> LoadData()).Wait();
}
return proyectos;
}
set
{
prope = value;
RaisePropertyChanged();
}
}
async private Task LoadData()
{
Prope = await clsStaticClassDataLoader.GetDataFromWebService();
}
这种方法有效,但我不喜欢使用 .等等,因为如果服务响应不快,这可能会冻结屏幕。
你能指导我这件事吗?
提前致谢
我处理这个问题的方式是在构造对象时开始加载属性的过程,但我没有等待结果。 由于属性在填充时通知,因此绑定工作正常。 本质上它的工作原理是这样的:
public class MyClass : INotifyPropertyChanged
{
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get { return prope; }
set { prope = value; RaisePropertyChanged(nameof(Prope)); }
}
public MyClass()
{
// Don't wait or await. When it's ready
// the UI will get notified.
LoadData();
}
async private Task LoadData()
{
Prope = await clsStaticClassDataLoader.GetDataFromWebService();
}
}
这工作得很好,并且不会导致 UI 中的任何延迟或卡顿。 如果希望集合永远不会null
(IMO 的良好做法(,则可以使用空集合预初始化prope
字段。
我建议你阅读我关于异步MVVM数据绑定的MSDN文章。我有一个提供NotifyTask<T>
类型的库(github链接(,可以这样使用:
public class MyClass : INotifyPropertyChanged
{
public NotifyTask<ObservableCollection<CProyecto>> Prope { get; private set; }
public MyClass()
{
// Synchronously *start* the operation.
Prope = NotifyTask.Create(LoadDataAsync());
}
async private Task<ObservableCollection<CProyecto>> LoadDataAsync()
{
return await clsStaticClassDataLoader.GetDataFromWebService();
}
}
然后,您的数据绑定将在 Prope.Result
上运行。
这种方法的优点是还可以使用数据绑定来隐藏/显示忙碌指示器 ( Prope.IsNotCompleted
(、显示数据可用时的控件 ( Prope.IsSuccessfullyCompleted
( 和错误通知 ( Prope.IsFaulted
/Prope.ErrorMessage
(。
此外,如果需要,可以指定非null
默认值:
Prope = NotifyTask.Create(LoadDataAsync(), new ObservableCollection<CProyecto>());
您当前对 Prope
属性的实现没有多大意义。在后台线程上执行 LoadData
方法是没有意义的,因为当您调用 Wait()
时,您无论如何都会阻止主线程。您不妨直接对 LoadData()
方法返回的任务调用 Wait()
:
//BAD IMPLEMENTATION!
private ObservableCollection<CProyecto> prope;
public ObservableCollection<CProyecto> Prope
{
get
{
if (prope == null)
LoadData().Wait();
return proyectos;
}
set { prope = value; RaisePropertyChanged(); }
}
上面的实现仍然是一个糟糕的实现。属性的 getter 不应执行异步操作。你应该阅读@Stephen Cleary关于这个主题的博客文章:https://blog.stephencleary.com/2013/01/async-oop-3-properties.html
。并在他的AsyncEx
图书馆中查看他的NotifyTaskCompletion
类型:https://github.com/StephenCleary/AsyncEx