Неблокирующие ленивые свойства в модели MVVM

Я новичок в MVVM, поэтому, пожалуйста, извините меня, если эта проблема имеет хорошо известное решение.

Мы создаем кучу классов моделей, у которых есть некоторые основные свойства, которые загружаются спереди, а также некоторые дополнительные свойства, которые могут быть ленивы загружены по требованию, вызывая вызов веб-API (обновление: для уточнения, это был бы вызовом веб-API на лениво загруженное свойство).

Вместо того, чтобы иметь несколько моделей, кажется разумным иметь одну модель с логикой ленивой загрузки. Однако также кажется, что свойства lazy-loaded не должны блокироваться при доступе, так что, когда View связывается с ViewModel и привязывается к модели, мы не блокируем поток пользовательского интерфейса.

Как таковой, я думал о шаблоне что-то вроде того, когда к нему обращается ленивое свойство в модели, он начинает асинхронную выборку, а затем сразу возвращает значение по умолчанию (например, null). Когда асинхронная выборка будет завершена, она поднимет событие PropertyChanged, чтобы ViewModel/View мог повторно привязываться к выбранному значению.

Я пробовал это, и кажется, что он работает очень хорошо, но задавался вопросом:

  • Есть ли какие-то подводные камни к этому подходу, о которых я еще не узнал, но столкнется с тем, что приложение будет увеличиваться по сложности?
  • Существует ли существующее решение этой проблемы, встроенное в структуру или широко используемое как часть сторонней структуры?

Ответ 1

В прошлом я делал что-то подобное, и я забыл о том, что вы не можете назвать свое свойство async каким-либо кодом и ожидать, что он будет иметь значение.

Итак, если я lazy-load список 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 с сервера, мне нужно было знать, что метод async работал правильно и фактическое значение было нулевым, чтобы он не перезапускал метод async.

Я также не хотел, чтобы метод async запускался дважды, если кто-то вызвал метод Get во второй раз до того, как завершился первый асинхронный вызов.

Я решил это в то время, имея свойство Is[AsyncPropertyName]Loading/ed для каждого свойства async и установив его в true во время первого асинхронного вызова, но мне не очень понравилось создавать дополнительное свойство для всех свойств async.