The ViewModel method template

ViewModels are the DDD equivalent of application level services and have two basic three basic responsibilities:

  • Start and manage domain level workflows and transactions.
  • Keep track of the state of the current view (or event the complete application).
  • Translate domain objects and states into a representation that can be displayed by the view.

Over time, we got to some standard for methods on ViewModels, that resulted in a template methods that handle „everything“, and we can then just pick the things we need.

As many Apps represent some server data, ViewModels tend to have a certain set of methods:

  • LoadData/Activate():
    Called every time, a View loads with the ViewModel as it’s datacontext. It makes sure all data is loaded correctly.
  • UpdataDataItems():
    Loads all data, that is currently available.
  • Refresh():
    Refreshes data from the web.

(Yes, these are quite similar to MvvmCross’s init(), start() and reloadState() methods.)

LoadData()

LoadData() is called when a view loads a ViewModel as it’s data context. This methods fill itself with data and (when required) starts a refresh to get the latest and greatest data from some service.

This is also the place to take on parameters that are submitted by the view loading this model.

public async Task LoadDataAsync()
{
    if (!IsDataLoaded)
        await UpdateDataItemsAsync();

    if (NetworkHelper.IsNetworkConnectionAvailable && UpdateTimerHelper.ShouldUpdate("Employees"))
        await RefreshAsync();
}

UpdateDataItems()

This is the common place to pick up all data that is already available: Locally cached items.

Loading the first data is intended to be fast. Is should be available almost at an instant, so the user has something to view and interact with, while the update operation starts in the background.

private async Task UpdateDataItemsAsync()
{
    // Get items from local cache
    var employees = (await _employeeService.GetEmployeesAsync()).OrderBy(e => e.Sorting).ToList();
    Employees = new ObservableCollection<Employee>(employees);

    IsDataLoaded = true;
}

Refresh

Refresh() is actually the first real operation of the ViewModel. Like most methods on ViewModels, it does not have a return type except Task. Usually, they are called from some event handler (like button clicks) which are void returning and therefore cannot really await anything. Updates happen via the INotifyPropertyChanged anyway.

ViewModel methods should never throw exceptions (see: [The exception barrier]). That’s why most of our ViewModel methods look like this:

public async Task RefreshAsync()
{
    // Precondition check
    if(IsDataLoading) return;
    IsDataLoading = true;

    // Preparations
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
    
    try
    {
        // Run the actual operation
        await _employeeService.RefreshAsync(cts.Token);
        await UpdateDataItemsAsync();

        UpdateTimerHelper.SetUpdate("Employees");
    }
    catch (HttpRequestException)
    {
        _notificationService.Notify(ApplicationConstants.Text_NoInternet);
    }
    catch (OperationCanceledException)
    {
        // Cancelled because of timeout
        if (cts.IsCancellationRequested)
            _notificationService.Notify(ApplicationConstants.Text_Timeout);
    }
    catch
    {
        // Just to annoy developers, until they got all their error cases checked.
        System.Diagnostics.Debugger.Break();
    }
    
    IsDataLoading = false;
}

This is an „all-in“ example:

  • Before running the methods, application level preconditions are validated: Are we updating already?
  • Preparations like task extenders, CancellationTokens, etc. are made.
  • The actual method gets executed.
  • All error cases get handled.
We usually put an extra ´Debugger.Break()´in the last catch clause. This shouldn’t activate at all, but if it does, the developer knows he has some unmatched error cases. Hopefully, it is annoying enough to bring him to handle it. :)
Advertisements
The ViewModel method template

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s