Monday, April 07, 2014

A busy MvxViewController for MvvmCross + iOS

In my MVVMCross apps, in the shared PCL core library, I usually have a MvxViewModel derived class called ViewModelBase with a IsBusy property:

public class ViewModelBase : MvxViewModel
bool isBusy;
public bool IsBusy
get { return this.isBusy; }
set { if (this.isBusy != value) { this.isBusy = value; this.RaisePropertyChanged("IsBusy"); } }

// other base stuff in ViewModelBase
The property is to update a progress indicator control in the view.
For iOS the control can be UIActivityIndicatorView.

But instead of placing a UIActivityIndicatorView on each view, we can dynamically create it at run-time when IsBusy property changes to true.
We can have this implemented in a ViewController base class like this:

using System;
using System.ComponentModel;
using MonoTouch.ObjCRuntime;
using MonoTouch.UIKit;
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.CrossCore.WeakSubscription;
using YourApp.Core.ViewModels;

namespace YourApp.Touch
public abstract class MvxViewControllerBase : MvxViewController
// weak subscription to NotifyProperty event
IDisposable npSubscription;

public override void ViewDidLoad()

// subscribe to view-model's PropertyChanged
this.npSubscription = ((INotifyPropertyChanged)this.ViewModel).WeakSubscribe<bool>("IsBusy", (s, e) => { this.UpdateActivityIndicatorView(); });

// at this point view-model exists, so update the indicator view

// add other common UIViewController stuff

protected override void Dispose(bool disposing)
if (disposing && this.npSubscription != null)
this.npSubscription = null;

void UpdateActivityIndicatorView()
// get the activity indicator
var activityIndicatorView = (UIActivityIndicatorView)this.View.ViewWithTag(1000);

var vm
= (ViewModelBase)this.ViewModel;
if (vm.IsBusy)
// show busy indicator. create it first if it doesn't already exists
if (activityIndicatorView == null)
= new UIActivityIndicatorView(this.View.Frame)
= UIActivityIndicatorViewStyle.Gray,
= 1000


// show the activity indicator
activityIndicatorView.Hidden = false;
// hide the activity indicator
if (activityIndicatorView != null)
= true;
Instead of having a base class we can delegate the implementation to an extension class which has the same implementation.

Please let me know if you see any possible issues.

I am thinking to do a similar implementation for other platforms as well.
Maybe MVVMCross could support out of the box a similar implementation. A built in implementation in MVVMCross would probably require to be able to override the style for the indicator.

1 comment:

Kenton Pickard said...

This is almost a year old, but the way I've solved this is to create an IsVmBusy property in the BaseViewController and then use a binding (which will do the WeakSubscribe behind the scenes) to connect the VM.IsBusy value to the BaseViewController.IsVmBusy property. In the setter of the IsVmProperty I would call your method start or stop the activity indicator.