Asynchronous with TAP (async / await) in WPF MVVM

I am looking for best practice for the next setup.

A data view is tied to ViewModel (via WPF). View ViewModel View through INotifyPropertyChanged. ViewModel model updates through events. The model knows about things from the outside world, for example, how to get material from the Internet through WebClient and how to retrieve data from the database.

Receiving and sending materials to the outside world should be performed asynchronously so that the user interface (and, by extension, the user) can not suffer from the outside world.

What would be the best way to do this?

1 .. ViewModel should be responsible for calling asynchronous methods of the model.
That would have the advantage that you could write things like

GetWebPage(string url) { var result = await Model.GetWebPageAsync(url); Url = result.Url; } 

in ViewModel, where Url is the ViewModel property with INotifyPropertyChanged to update the view. Or even

 GetWebPage(string url) { var result = await Model.GetWebPageAsync(url); _view.Url = result.Url; } 

where we can avoid sharing INotifyPropertyChanged. Which of these methods do you prefer?

However, it would be more reasonable if the model itself did asynchronous work. We might want to use a model without View and ViewModel, but it will work asynchronously. Another argument is that who knows best that the model handles asynchronously best.

2. The model processes all asynchronous things by itself. ViewModel code is more like

 GetWebPage(string url) { Model.GetWebPage(url); } 

and in the model

 GetWebPage(string url) { var result = await Model.GetWebPageAsync(url); if (UrlChanged != null); UrlChanged(this, new UrlChangedEventArgs(url)); } 

so that the ViewModel can subscribe and update the View accordingly.

Which method do you think is best practice?

+6
source share
2 answers

Third way: the view model makes an asynchronous call, but uses the client service to retrieve the web page, the anemia model itself (it does not know anything about the outside world):

 GetWebPage(string url) { var dataService = anyServiceLocator.GetService<IDataService>(); var result = await dataService.GetWebPageAsync(url, Model); Url = result.Url; } 

This allows you to change the algorithm for loading real data, for example. for testing purposes.

+3
source

I believe that the best practice for the described scenario will be the one that you come up with - considering the pros and cons of each approach - and this will be specific to your task (since the requirements vary from task to task). Regarding the actual answer to the question, I believe that there is not much difference. Although now I am thinking of a different approach. Consider parameterizing the asynchronous behavior of the Helper object (possibly DownloadManager), which can be passed to the VM as a parameter. This will allow you to easily test both the VM and the model without distinguishing between the behavior, and check this behavior separately in the DownloadManager.

0
source

All Articles