Introducing TinyMvvm 2.0

TinyMvvm is a library that I created a couple of years ago. The idea was to build a small (tiny) MVVM library that made me more productive. I first released TinyNavigationHelper that helped med to abstract the Xamarin.Forms navigation, because I do not want my ViewModels to have references to Xamarin.Forms.

Last time I updated TinyMvvm was about one and a half year ago, the reason I have not updated it since then is that it has been stable and worked very well for me in multiple apps I have worked with for multiple clients.

When Xamarin.Forms Shell was released I started to work with some improvements to make TinyMvvm work with Xamarin.Forms Shell. But I never finished them, because the current version worked very well together with Shell. The only thing not supported was URL navigation.

But in the current app, I work with I had a use case where URL navigation would be very nice to use. Of course, I could have used it without using the navigation in TinyMvmm. But there are some great features of TinyMvvm that I missed then. For example to get navigation parameters in the ViewModel without having to pass them manually from the view and if I wanted to navigate from the ViewModel I had to add references to Xamarin.Forms inside of them.

New features

There is a couple of new stuff added to TinyMvvm in this release.

ShellNavigationHelper

If you want to use URL navigation together with TinyMvvm you have to use the ShellNavigtionHelper. ShellNavigationHelper is a subclass of FormsNavigationHelper.

var navigationHelper = new TinyNavigationHelper.Forms.ShellNavigationHelper();
navigationHelper.RegisterViewsInAssembly(appAssembly);
navigationHelper.RegisterView("MainView", typeof(MainView));

The method that is supporting URL navigation is the NavigateTo(string key) method. All other methods of INavigationHelper will use traditional Xamarin.Forms NavigationService. To NavigateTo you can either specify a URL or a key to a view. If it got a key that you have registered as in the code about it will use the traditional NavigationService, otherwise, it will use Shell navigation with URL.

await NavigationHelper.Current.NavigateTo("//home/messages?id=1");

If you are in a ViewModel with ViewModelBase as parent you can use the Navigation property of of the ViewModelBase,

await Navigation.NavigateTo("//home/messages?id=1");

QueryParameters in ViewModelBase

With URL navigation you can pass query parameters. With TinyMvvm you can access them from the ViewModel via the QueryParameters property of ViewModelBase. QueryParameters is of type Dictionary<string, string>.

public override async Task Initialize()
{
    await base.Initialize();

    var id = QueryParameters["id"];
}

Optimization

In TinyMvvm 1.x there was a dependency on TinyNavigationHelper, in 2.0 is TinyNavigationHelper added as a submodule and compiled into the same assembly as TinyMvvm. This reduces the amount of referenced assemblies that Xamarin.Forms have to search for custom renderers in.

Breaking changes

The constructor to FormsNavigationHelper has changed. You can not pass an instance of Xamarin.Forms.Application anymore, the reason is that it not is necessary to provide the navigation helper with it.

Obsolete fetures

The BeginInvokeOnMainThread future of ViewModelBase has been marked as obsolete, the recommendation is to use Xamarin.Essentials.MainThread.BeginInvokeOnMainThread instead.

TinyMvvm basics

Here are some of the basics of TinyMvvm, you will find the full docs and a sample project here, https://github.com/TinyStuff/TinyMvvm.

Initiation

TinyMvvm.Forms.TinyMvvm.Initialize();

ViewBase<T>

Features (or drawbacks) of the ViewBase

  • It creates the ViewModel for you if you inherit the ViewModel from ViewModelBase

The view should inherit from ViewBase<T> where T is the ViewModel. The ViewModel can be any class that has ViewModelBase as the base class.

ViewBase<T> itself inherits from Xamarin.Forms.ContentPage and can be treated by Xamarin Forms as any page.

If you decide to use ViewModelBase as the base class for your view model and at the same time have the IoC resolver enabled, the view will automatically create the view model for you when the view is created. Hence no need to inject the view model in the constructor and assign it manually. Feature or not, you decide.

An example of a typical page in TinyMvvm would look like this:

<tinymvvm:ViewBase x:TypeArguments="viewmodels:MainViewModel" 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:viewmodels="clr-namespace:TinyMvvm.Forms.Sample.ViewModels;assembly=TinyMvvm.Forms.Samples"
    xmlns:tinymvvm="clr-namespace:TinyMvvm.Forms;assembly=TinyMvvm.Forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    x:Class="TinyMvvm.Forms.Sample.Views.MainView">

</tinymvvm:ViewBase>

What you need to do is:

  • Define two namespaces (viewmodels and tinymvvm)
  • Change the view base type to tinymvvm:ViewBase
  • Add a type argument pointing to your ViewModel

### ViewModelBase

TinyMvvm also defines a base class for the view model called `ViewModelBase`.

Features of the ViewModelBase

* Wraps navigation for you through the INavigation interface (Implemented in TinyNavigation)
* Implements INotifyPropertyChanged for you
* Propagates life cycle events to the view (Initialize, OnAppearing, OnDisapparing)

### IoC
Tiny Mvvm is not bound to any specific IoC provider. There is a provider for Autofac that you can install with the "TinyMvvm.Autofac" package.

Install-Package TinyMvvm.Autofac

TinyMvvm has a Resolver in its core project. To use it you need to add on a provider to it that implements the IResolver interface, for example, our Autofac provider.

```csharp
var container = builder.Build();
var resolver = new AutofacResolver(container);
Resolver.SetResolver(resolver);
var navigationHelper = Resolver.Resolve();

TinyCommand

TinyMvvm has its own implementation of ICommand that not has any references to Xamarin.Forms so you can use it in a library without reference Xamarin.Forms.

public ICommand WithParameter
{
      get
      {
                return new TinyCommand(async() =>
                {
                   //Do stuff
                });
      }
}

  4/21/2020 - 9:45 PM