I'm fairly new to MVVM, so please excuse me if this problem has a well-known solution.
We are building a bunch of model classes which have some core properties that are loaded up-front, as well as some additional properties which could be lazy-loaded on demand by making a web API call (update: to clarify, it would be a web API call per lazily-loaded property).
Rather than having multiple models, it seems sensible to have a single model with the lazy-loading logic in there. However, it also seems that the lazy-loaded properties should not block when accessed, so that when the View binds to the ViewModel and it binds to the Model, we don't block the UI thread.
As such, I was thinking of a pattern something along the lines of when a lazy property on the Model is accessed it begins an asynchronous fetch and then immediately returns a default value (e.g. null
). When the asynchronous fetch is complete, it will raise a PropertyChanged
event so that the ViewModel/View can re-bind to the fetched value.
I've tried this out and it seems to work quite nicely, but was wondering:
I did something like this in the past and the one thing I kept forgetting about is you can't call your async property through any kind of code behind and expect it to have a value.
So if I lazy-load a list of Customer.Products
, I can't reference Customer.Products.Count
in the code-behind because the first time it's called the value is NULL or 0 (depending on if I create a blank collection or not)
Other than that, it worked great for the bindings. I was using the Async CTP library for making my async calls, which I found was absolutely wonderful for something like this.
public ObservableCollection<Products> Products
{
get
{
if (_products == null)
LoadProductsAsync();
return _products;
}
set { ... }
}
private async void LoadProductsAsync()
{
Products = await DAL.LoadProducts(CustomerId);
}
Update
I remember another thing I had issues with was data that actually was NULL. If Customer.Products actually returned a NULL value from the server, I needed to know that the async method had run correctly and that the actual value was null so that it didn't re-run the async method.
I also didn't want the async method to get run twice if someone called the Get method a 2nd time before the first async call had completed.
I solved this at the time by having an Is[AsyncPropertyName]Loading/ed
property for every async property and setting it to true during the first async call, but I wasn't really happy about having to create an extra property for all async properties.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With