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
}
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()
{
base.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
this.UpdateActivityIndicatorView();
// add other common UIViewController stuff
}
protected override void Dispose(bool disposing)
{
if (disposing && this.npSubscription != null)
{
this.npSubscription.Dispose();
this.npSubscription = null;
}
base.Dispose(disposing);
}
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)
{
activityIndicatorView = new UIActivityIndicatorView(this.View.Frame)
{
ActivityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray,
Tag = 1000
};
this.Add(activityIndicatorView);
this.View.BringSubviewToFront(activityIndicatorView);
activityIndicatorView.StartAnimating();
}
// show the activity indicator
activityIndicatorView.Hidden = false;
}
else
{
// hide the activity indicator
if (activityIndicatorView != null)
{
activityIndicatorView.Hidden = true;
}
}
}
}
}
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.
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.
ReplyDelete