MVVM c# 如何将异步数据加载到属性中



我想知道是否有更好的方法将异步数据加载到属性中。 现在我创建一个异步函数并在属性的 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

最新更新