MVVM模式中的非阻塞懒加载属性

14

我对MVVM比较新,如果这个问题有众所周知的解决方案,请原谅我。

我们正在构建一堆模型类,其中包含一些核心属性,这些属性是预先加载的,以及一些其他属性,可以通过调用Web API进行按需延迟加载(更新:为了澄清,每个延迟加载的属性都会进行一次Web API调用)。

与其拥有多个模型,使用一个单一的带有延迟加载逻辑的模型似乎更合理。但是,延迟加载的属性在访问时似乎不应该阻塞,以便当View绑定到ViewModel并且它绑定到Model时,我们不会阻塞UI线程。

因此,我考虑使用以下类似的模式:当访问模型上的惰性属性时,它会开始异步获取,然后立即返回默认值(例如null)。完成异步获取后,它将引发PropertyChanged 事件,以便ViewModel / View可以重新绑定到获取的值。

我尝试过这种方法,它似乎运行得很好,但是有以下疑问:

  1. 这种方法是否存在任何潜在问题,在应用程序复杂度增加时会遇到这些问题吗?
  2. 是否存在已存在解决此问题的解决方案,无论是内置于框架中还是作为第三方框架的组成部分广泛使用?

我能想到的可能问题是,你需要监听所有这些延迟加载器上的PropertyChanged事件,这意味着如果你有一个依赖于多个这些加载器的属性或函数,它将不得不等待所有它依赖的加载器完成后才能执行自己的代码。 这可能会导致必须编写大量逻辑,否则可以将获取延迟加载器的“同步”操作作为单线程调用在该单独线程中组合。 - Timothy Groote
@Timothy - 很好的观点。我已经考虑过了,我的感觉是由于惰性加载数据的特性,不太可能有任何东西依赖于多个惰性数据片段。很可能有多个东西依赖于单个惰性数据,但我认为这并不会造成问题。 - Greg Beech
我使用了你上述描述的方法,效果非常好。 - Jeff
1个回答

11
我曾经做过类似的事情,但唯一让我忘记的是不能通过任何代码来调用异步属性并期望它有一个值。因此,如果我惰性加载一个列表Customer.Products,我不能在代码后台中引用Customer.Products.Count,因为第一次调用时该值为NULL或0(取决于是否创建了空集合)。除此之外,绑定效果非常好。我使用Async CTP库来进行异步调用,我发现它非常适合这样的场景。
public ObservableCollection<Products> Products
{
    get
    {
        if (_products == null)
            LoadProductsAsync();

        return _products;
    }
    set { ... }
}

private async void LoadProductsAsync()
{
    Products = await DAL.LoadProducts(CustomerId);
}

更新

我记得另一个我遇到问题的事情是数据实际上为NULL。如果Customer.Products从服务器返回了NULL值,我需要知道异步方法已经正确运行,并且实际值为null,以便它不会重新运行异步方法。

如果在第一个异步调用完成之前,有人第二次调用Get方法,我也不希望异步方法被运行两次。

当时我通过为每个异步属性设置一个Is[AsyncPropertyName]Loading/ed属性并在第一个异步调用期间将其设置为true来解决这个问题,但我并不满意必须为所有异步属性创建额外的属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接