MvvmMobile is an MVVM framework developed for Xamarin iOS and Xamarin Android with a focus on abstracted navigation. This ensures high testability of the viewmodel classes.
Mikael Stalvik
Jonas Frid
- Create a .NET Standard project for the shared code
- Setup the IoC Container
- Create a Xamarin iOS project
- Create a Xamarin Android project
- Create a .NET Standard (version 2.0 or later) project for your shared code and add a reference to MvvmMobile.Core
- Make sure that all viewmodel interfaces inherit from IBaseViewModel
- Make sure that all viewmodel classes inherit from BaseViewModel
When navigating from one viewmodel to another, resolve INavigation and call the method NavigateTo.
var navigation = Mvvm.Api.Resolver.Resolve<INavigation>();
navigation.NavigateTo<IMySecondViewModel>(payload, ReturnAction);
The 'payload' is an instance of a class that implements IPayload and this is a way to pass a payload of data to the receiving viewmodel.
The 'ReturnAction' is an Action that is called (with an optional payload) when navigating back to the viewmodel (a callback).
To return to the previous viewmodel and optionally pass a payload, just call NavigateBack from the viewmodel.
var payload = Mvvm.Api.Resolver.Resolve<ISomePayload>();
payload.SomeData = someData;
NavigateBack(payload);
MvvmMobile does not contain an IoC container. This has been abstracted away and enables you to use the IoC solution of your choosing!
First, create a class that implements MvvmMobile.Core.Common.IResolver. Example with Autofac:
public class AutofacResolver : MvvmMobile.Core.Common.IResolver
{
private readonly IContainer _container;
public AutofacResolver(IContainer container)
{
_container = container;
}
public bool IsRegistered<T>() where T : class
{
return _container.IsRegistered<T>();
}
public T Resolve<T>() where T : class
{
if (IsRegistered<T>() == false)
{
return default(T);
}
return _container.Resolve<T>();
}
}
Then, create a class that implements MvvmMobile.Core.Common.IContainerBuilder. Example with Autofac:
public class AutofacContainerBuilder : MvvmMobile.Core.Common.IContainerBuilder
{
private readonly ContainerBuilder _containerBuilder;
public AutofacContainerBuilder()
{
_containerBuilder = new ContainerBuilder();
}
public MvvmMobile.Core.Common.IResolver Resolver { get; private set; }
public void Register<TInterface>(TInterface instance) where TInterface : class
{
_containerBuilder?.RegisterInstance(instance).As<TInterface>();
}
public void Register<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
_containerBuilder?.RegisterType<TImplementation>()?.As<TInterface>();
}
public void RegisterSingleton<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
_containerBuilder?.RegisterType<TImplementation>()?.As<TInterface>()?.SingleInstance();
}
public void Build()
{
var container = _containerBuilder.Build();
Resolver = new AutofacResolver(container);
}
}
The instance of your IContainerBuilder class is then passed to MvvmMobile with the init process described below for the plattforms.
- Create a Xamarin iOS project
- Add a reference to your shared project
- Add references to MvvmMobile.Core and MvvmMobile.iOS
- Create your view controllers
All view controllers must inherit from ViewControllerBase or one of the other view controller base classes provided by MvvmMobile.
If you use storyboards then you need to add the Storyboard attribute to your view controller class.
[Storyboard(storyboardName:"TheNameOfTheStoryBoard", storyboardId:"TheIdOfTheViewControllerInTheStoryboard")]
public partial class MyFirstController : ViewControllerBase<IMyFirstViewModel>
Your view controllers can override ViewModel_PropertyChanged to be notified of property changes in the connected view model.
protected override void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ViewModel.SomeProperty))
{
SomeTextField.Text = ViewModel.SomeProperty;
}
}
In AppDelegate.cs and the FinishedLaunching method. Initialize MvvmMobile with the IoC container builder instance created above and the mapping between your viewmodels and your view controllers.
MvvmMobile.iOS.Bootstrapper.SetupIoC(builder);
builder.Build();
MvvmMobile.iOS.Bootstrapper.Init(new Dictionary<Type, Type>
{
{ typeof(IMyFirstViewModel), typeof(MyFirstController) },
{ typeof(IMySecondViewModel), typeof(MySecondViewController) }
});
- Create a Xamarin Android project
- Add a reference to your shared project
- Add references to MvvmMobile.Core and MvvmMobile.Droid
- Create your activities and fragments
All activities must inherit from ActivityBase and all fragments must inherit from FragmentBase.
Your activities/fragments can override ViewModel_PropertyChanged to be notified of property changes in the connected view model.
protected override void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ViewModel.SomeProperty))
{
SomeEditText.Text = ViewModel.SomeProperty;
}
}
In your application class. Initialize MvvmMobile with the IoC container builder instance created above and the mapping between your viewmodels and your activities/fragments.
MvvmMobile.Droid.Bootstrapper.SetupIoC(builder);
builder.Build();
MvvmMobile.Droid.Bootstrapper.Init(new Dictionary<Type, Type>
{
{ typeof(IMyFirstViewModel), typeof(MyFirstActivity) },
{ typeof(IMySecondViewModel), typeof(SomeFragment) }
});
For a more detailed view of MvvmMobile, have a look at the sample project included in this repo! Happy coding!