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
                });
      }
}

Introducing TinySvgHelper

For a pretty long time I have had code that I have used for a couple of different apps that uses SkiaSharp to convert an svg image to a Xamarin.Forms ImageSource. I also blogged about it two years ago, https://danielhindrikes.se/index.php/2018/03/13/use-skiasharp-to-convert-svg-to-xamarin-forms-imagesource/. But I never released it as a library until now.

Get started with TinySvgHelper

The library is published to NuGet, https://www.nuget.org/packages/TinySvgHelper/

To install it, search for TinySvgHelper in the **Nuget Package Manager** or install it with the following command:

Install-Package TinySvgHelper

To use it you must add SvgHelper.Init() to your MainActivity and/or AppDelegate.

MainActivity

protected override void OnCreate(Bundle savedInstanceState)
{
    ....
 
    SvgHelper.Init();
 
    ...
}

AppDelegate

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    ...
 
    SvgHelper.Init();
 
    ...
}

Use TinySvgHelper

You can use TinySvgHelper either from your XAML- or C# code. For iOS add the svg files to the **Resources** folder and for Android add the svg files to the **Assets** folder.

XAML

First you need to import the namespace:

xmlns:svg="clr-namespace:TinySvgHelper;assembly=TinySvgHelper"

Then you will use it as a markup extension:

<Image Source="{svg:Svg FileName='logo.svg', Height=200,Width=200}" />

You can also specify a color to it:

<ShellContent Icon="{svg:Svg FileName='info.svg', Height=22,Width=22,Color=Black}" Title="Start">
    <views:StartView />
</ShellContent>
```
 
### C#
<pre lang="csharp">
using TinySvgHelper;
var image = new Image();
image.Source = SvgHelper.GetAsImageSource("info.svg", 50, 50, Color.Blue);

Read more

You can find the full documentation, the code and a sample project on GitHub, https://github.com/TinyStuff/TinySvgHelper

Application Insights for Xamarin- and UWP apps with TinyInsights

About two and a half years ago I created a library with the name TinyInsights with the idea to abstract away the underlying provider for diagnostics and analytics. The reason was that I wanted to make it possible to change the provider without that it affected my code more than in the initial setup of the app. Because diagnostics- and analytics services have a tendency to come and go, for example, Xamarin Insights and HockeyApp are no longer with us. Instead, we now have AppCenter, which also was my first provider for TinyInsights. I also wanted to make it possible to use multiple providers at the same time, because I have worked with apps where business analysts want the data to be in Google Analytics and developers want another service because other services are better for finding errors in apps.

My default provider has been AppCenter the last years, but recently I have missed a couple of important features and you can not analyze the data any deeper. You can export the data to Application Insights and then you can create deeper reports etc. But the way AppCenter store data make some questions harder to make in a good way. For example, if you want to track page views, you have to do that as an event. Application Insights is not built to handle page views that way, because it has real support for page views. AppCenter also lacks the future of tracking dependencies.

So what I decided to do was to create a new provider to TinyInsights with support for Application Insights. But I still using AppCenter for crashes and errors, because it also supporting me to upload symbols to it and Application Insights have no good way to distinguish between an error and a crash. But when I am logging crashes to Application Insights I am setting a custom property with the name "IsCrash" to "true".

I have implemented TrackDependency to all providers, but for AppCenter it only saves all data as custom properties and there is no good way to visualize them, but the data is there if you want to export it to your own visualizer.

Below I have written a short introduction about how to get started with the ApplicationInsightsProvider and TinyInsights in general.

Initializing Application Insights Provider

When initializing TinyInsights you need to specify what provider or providers you want to use. For Application Insights, you only need to give it the IntrumentationKey. If you don't pass different keys for different platforms all data will be collected together and not as in AppCenter where you create one app per platform.

var appInsights = new ApplicationInsightsProvider("{InstrumentationKey}");
var appCenter = new AppCenterProvider("{keyForIOS}", "{keyForAndroid}", {keyForUWP});
appCenter.IsTrackPageViewsEnabled = false;
appCenter.IsTrackEventsEnabled = false;
appCenter.IsTrackDependencyEnabled = false;
 
TinyInsights.Configure(appCenterProvider, applicationInsightsProvider);

Handling exceptions

To track exceptions/errors, just use the TrackErrorAsync method. Crashes will automatcially be tracked and sent to Application Insights next time the user is starting the app.

catch(Ecception ex)
{
     await TinyInsights.TrackErrorAsync(ex);
}
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
catch(Ecception ex)
{
     await TinyInsights.TrackErrorAsync(ex, properties);
}

Tracking dependencies

There are a two of ways to track dependencies with TinyInsights.
The first and the basic method is TrackDependencyAsync, and is also used in the background by the other way to do it.

var startTime = DateTimeOffset.Now;
 
var success = await GetData();
 
var duration = DateTimeOffset.Now - startTime
 
await TinyInsights.TrackDependencyAsync("api.mydomain.se", "https://api/mydomain.se/v1/data/get", startTime, duration, success);

The second way is to create a TinyDependency object that handles most of the tracking for you. You will do that by just by wrapping your code for the dependency in a using statement.

using (var tracker = TinyInsights.CreateDependencyTracker("api.mydomain.se", "https://api/mydomain.se/v1/data/get"))
{
     await GetData();
}

If the dependency succeded that is fine, but if it not you need to handle that on your own, using the Finish method of the TinyDependency object.

using (var tracker = TinyInsights.CreateDependencyTracker("api.mydomain.se", "https://api/mydomain.se/v1/data/get"))
{
     try
     {
          var repsonse = await GetData();
 
          if(!response.IsSuccessStatusCode)
          {
               await tracker.Finish(false, (int)response.StatusCode);
          }
     }
     catch(Exception ex)
     {
          tracker.Finish(false, ex);
     }
}

Tracking page views

To track page views, just use the TrackPageViewAsync method.

await TinyInsights.TrackPageViewAsync("SuperCoolView");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackPageViewAsync("SuperCoolView", properties);

Tracking events

To track events, just use the TrackEventAync method.

await TinyInsights.TrackEventAsync("SuperCoolEvent");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackEventAsync("SuperCoolEvent", properties);

Feedback

If you have any feedback, please create an issue on GitHub. You will also be welcome to contribute to the library with improvments or/and other providers.
 

TinyCache 2.0

TinyCache, https://github.com/TinyStuff/TinyCache, is an open-source library created by Mats Törnberg and it is a part of the collection of libraries that we call TinyStuff. It is a library that makes caching a little bit easier.

Today we are releasing version 2.0 of TinyCache. In the first version, you could only have a single instance of TinyCahce. But I made some changes and added a pull request to the library that makes it possible to have multiple instances. The reason for that is that sometimes I wanted to have different settings for the cache in different situations in the same app. If you have used TinyCache before, an update to 2.0 will break your code. This blog post will introduce you to the new changes, but also to how TinyCache is working if you don't have used it before.

TinyCacheHandler

TinyCache 2.0 introduces TinyCacheHandler that will handle the instances of TinyCache. To make this possible, TinyCache and its method is no longer static.

If we only want one instance of TinyCache, we can use the Default method of TinyCacheHandler. The first time you access the Default property a new instance of TinyCache will be created if there are no instances created. This instance will get default as the key.

Create an additional instance of TinyCache

To add a new instance of TinyCacheHandler we can use either the create method or the add method.

Using the Create method:

var newCache = TinyCacheHandler.Create("myNewCache");

Using the Add method:

var newCache = new TinyCache();
TinyCacheHandler.Add("myNewCache", newCache);

Set default cache

If we have multiple cache instances, we may not want the first one to be the default, then we can change that bypassing the cache key to the SetDefault method of TinyCacheHandler.

TinyCacheHandler.SetDefault("myNewCache");

Get a specific instance of TinyCache

If we want to get an instance of TinyCache that not are the default instance, we can use the key for the instance as in the code below.

var cache = TinyCacheHandler.Get("myNewCache");
 
var result = cache.RunAsync<List<Data>>("myNewCache", () => { return api.GetData("customdata"); });

Use TinyCache

To use TinyCache, just use the RunAsync method and pass the cache key and how to fetch the data. If there are data in the cache, it will return cached data.

// Fetch data with default policy
var result = await TinyCacheHandler.Default.RunAsync<List<Data>>("cachekey", () => { return api.GetData("customdata"); });

TinyCache policies

With policies you can set how the cache should work, when should it refresh data etc.

Here is an example how we can use policies:

TinyCacheHandler.Default.SetBasePolicy(
    new TinyCachePolicy()
        .SetMode(TinyCacheModeEnum.CacheFirst) // fetch from cache first
        .SetFetchTimeout(TimeSpan.FromSeconds(5)) // 5 second excecution limit
        .SetExpirationTime(TimeSpan.FromMinutes(10)) // 10 minute expiration before next fetch
        .SetUpdateCacheTimeout(50) // Wait 50ms before trying to update cache in background

TinyCache stores

If we use TinyCache without setting a store, it will only cache data in the memory. But if we want to persist the data there are a couple of options. I mostly use the file storage store.

TinyCache.FileStorage
Is provided by the NuGet package, TinyCache.FileStorage. This store is persisting the cache data to a file at the filesystem of the device.

var store = new FileStorage();
 
var cacheFolder = string.Empty;
 
#if __IOS__ || __MACOS__
            cacheFolder = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User)[0];
#elif __ANDROID__
            cacheFolder = Application.Context.CacheDir.AbsolutePath;
#elif __UWP__
            cacheFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#else
            cacheFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
#endif
 
store.Initialize(cacheFolder);
 
// Set cache storage
TinyCacheHandler.Default.SetCacheStore(store);

TinyCache.Forms
Is provided by the NuGet package, TinyCache.Forms. This store is using the property storage that is provided by the Application class in Xamarin.Forms

var store = new XamarinPropertyStorage();
 
// Set cache storage
TinyCacheHandler.Default.SetCacheStore(store);

Read more

You will find both the documentation and the source code in the GitHub repository, https://github.com/TinyStuff/TinyCache.

TinyInsights – A library for helping developers with analytics and crash reporting

There are a lot of great analytics services out there. But I always use to create wrappers around their native SDK:s so I easily can replace them. But what I did with TinyInsights is that I added support for multiple service providers. That makes it possible to track data to multiple destinations with one common call. Right now TinyInsights has providers for AppCenter and Google Analytics. I will create more providers when I need them in projects I working on. But you are very welcome to contribute with more providers.

Install and configure TinyInsights

TinyInsights core package: https://www.nuget.org/packages/TinyInsights/
TinyInsights.AppCenter: https://www.nuget.org/packages/TinyInsights.AppCenter/
TinyInsights.GoogleAnalytics: https://www.nuget.org/packages/TinyInsights.GoogleAnalytics/

During the startup of the app, you need to do some configuration to get started. If you do not want the Google Analytics provider to catch unhandled exceptions you need to pass false to the constructor. For the AppCenter provider, it is always on.

var appCenterProvider = new AppCenterProvider(iOSKey, AndroidKey, UWPKey)
TinyInsights.Configure(appCenterProvider);

And with multiple providers:

var appCenterProvider = new AppCenterProvider(iOSKey, AndroidKey, UWPKey)
 
var catchUnhandledExceptions = false;
var googleAnalyticsProvider = var googleAnalyticsProvider = new GoogleAnalyticsProvider(googleAnalyticsKey, catchUnhandledExceptions);
 
TinyInsights.Configure(appCenterProvider, googleAnalyticsProvider);

ITinyInsightsProvider interface that should be implemented for each provider has three properties that you can use to configure what the provider should track. The default value is true;

provider.IsTrackErrorEnabled = false;
provider.IsTrackPageViewsEnabled = false;
provider.IsTrackEventsEnabled = false;

Google Analytics provider

The google analytics provider is platform specific so you need to do the configuration in your platform projects (or in a shared project).

Track errors

catch(Ecception ex)
{
await TinyInsights.TrackErrorAsync(ex);
}

Track page views

If you are using the AppCenter provider, page views will appear as a custom event.

await TinyInsights.TrackPageViewAsync("SuperCoolView");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackPageViewAsync("SuperCoolView", properties);

Track custom events

await TinyInsights.TrackEventAsync("SuperCoolEvent");
 
//with properties
var properties = new  Dictionarty<string, string>();
properties.Add("MyFirstProperty", "MyFirstValue");
properties.Add("MySecondProperty", "MySeconndValue");
 
await TinyInsights.TrackEventAsync("SuperCoolEvent", properties);

Google Analytics provider notes

If you are using the Google Analytics provider, you need to pass a property with key "action".

Custom tracking

If you want to change the way a provider is tracking data, all methods are virtual so you can create your own overrides in a subclass.

Create a provider

If you want to create an own provider, the only thing you need to do to get it work with TinyInsights is to implement the ITinyInsightsProvider interface. If you are creating an own provider I will be very happy if you create a pull request to the original repository on GitHub, https://github.com/TinyStuff/TinyInsights.

TinyMvvm – The best MVVM library for Xamarin.Forms!?

I have used many different MVVM frameworks/libraries, MvvmLight, Prism, MvvmCross etc. But I have not found any library that I think works great with Xamarin.Forms.

When I created TinyNavigationHelper I had an idea about that I did not needed an MVVM library and that it was enough to have an abstraction for the navigation part, so I could navigate from view models without passing the navigation service from Xamarin.Forms to it. I like to keep any UI frameworks away from my view models, so I do not want to have a dependency on Xamarin.Forms in my view models.

But after a few projects, I realized that I often wrote the same code again, again and again for every new project I started to work with. So I decided to create a library that contained the code I use to rewrite for each and every project, and the result of that is TinyMvvm. TinyMvvm is open source with MIT license and you can find the code on GitHub, https://github.com/TinyStuff/TinyMvvm. On GitHub can you also find the complete documentation including a sample project.

While I liked to use TinyNavigationHelper for navigation I decided to use that library inside of TinyMvvm for handling navigation. One thing that was important for me was that navigation should work well with TabbedPage and MasterDetailPage, I also wanted to be able to have navigation pages in modals. For example, if you are in a TabbedPage with one NavigationPage for each tab, I only want to navigate inside the selected tab. TinyNavigationHelper will handle that for you without the need to write extra code for that.

If you want to read more about navigation, I recommend you to read the blog post I wrote about TinyNavigationHelper, http://danielhindrikes.se/index.php/2017/09/14/tinynavigationhelper-for-xamarin-forms/.

TinyMvvm is created for Xamarin.Forms, but it is architecture in a way that not will lock it to Xamarin.Forms. There is a Xamarin.Forms specific package that contains the UI part of TinyMvvm, but the core package could be used on every platform that supports .NET Standard.

Some people will probably think TinyMvvm probably breaks one or more MVVM rules, but TinyMvvm is created to make me be more productive when building apps with Xamarin.Forms using an MVVM pattern.

Setup TinyMvvm for Xamarin.Forms

There are three things (two if you do not want to use IoC),
the first thing is to configure navigation:

// Option 1:
var navigationHelper = new NavigationHelper(this);
navigationHelper.RegisterView<MainView>("MainView");
 
// Option 2: Register single views		
var navigationHelper = new FormsNavigationHelper(this);		
navigationHelper.RegisterView("MainView", typeof(MainView));		
 
// Option 3: Register all views (pages) that is inherited from Page		
// The class name will be the key. To use this, you need to add using System.Reflection;		
var asm = typeof(App).GetTypeInfo().Assembly;		
navigationHelper.RegisterViewsInAssembly(asm);

Next step is to setup IoC. TinyMvvm has a resolver that the library uses for resolving types and you can also use it when you need it.

var container = builder.Build();
 
var autofacResolver = new AutofacResolver(container);
 
Resolver.SetResolver(autofacResolver);

The last thing you need to do is to call the Initialize method of TinyMvvm.

TinyMvvm.Forms.TinyMvvm.Initialize();

Set MainPage

You can set MainPage in App.xaml.cs (or App.cs if you do not use XAML) if you want, but the recommended way is to use the SetRootViewMethod of the navigationHelper.

NavigationHelper.Current.SetRootView("MyGreatMainView");

ViewModelBase

ViewModelBase is an abstract class that you can use as a base for your view models, it is implementing the INotifyPropertyChanged interface and has properties for IsBusy, IsNotBusy and Navigation etc.

Lifecycle overrides

In a view model that inherits from ViewModelBase, you can override three methods for handling the lifecycle for a view. The reason that I built this was that it tends that I often created methods for OnAppearing in the view model and called them from the OnAppearing from the view and I think it would be nice to have this in the view model without having to write code in the view every time.

Initialize

This will run only after that a ViewModel is created. It is recommended that you are using this method for loading data for the ViewModel. If you are passing parameters during navigation the parameter will be available here, use the NavigationParameter property to access the parameter. NavigationParameter cannot be used in the constructor for the view model.

OnAppearing

This method is called when a user navigates to a view, the first time or when a user returning to a view. I use to use this method for refreshing data. If I have events I use to subscribe to them here, so they will be restored when the user returning to the view while I use to unsubscribe from them when the user leaving the view.

OnDisappearing

This method will run when the user leaving a view. I use to use this for unsubscribing to events.

public class MyViewModel : ViewModelBase
{
     public override async Task Initialize()
     {
          var id = (int)NavigationParameter;
     }
 
     public override async Task OnAppearing()
     {
     }
 
     public override async Task OnDisappearing()
     {
     }
}

Navigation

You can access the NavigationHelper with the Navigation property in ViewModelBase, but you also have a NavigateTo command (implemented by Johan Karlsson) that makes it possible to trigger navigation from your XAML without adding anything to your view model. The only thing you have to do is to send the view key as a command parameter.

<Buttom Command="{Binding NavigateTo}" CommandParameter="TheKeyForTheGreatViewYouWantToNavigateTo" />
public ICommand GoToView => new TinyCommand(async() => await Navigation.NavigateToAsync("TheKeyForTheGreatViewYouWantToNavigateTo"));
 
public ICommand GoBack => new TinyCommand(async() => await Navigation.BackAsync());

TinyCommand

While we do not want to have references to Xamarin.Forms in our ViewModels TinyMvvm has an own ICommand implementation, TinyCommand.

ViewBase

With TinyMvvm you can use ViewBase as your base class instead of ContentPage. ViewBase is a ContentPage but it added some extra nice features. There are one ViewBase and one ViewBase where T : INotifyPropertyChanged. The generic one makes it possible to set BindingContext from XAML. If you want Initialize, OnAppearing and OnDisappering in your view models to work you have to some of the ViewBase variants.

<local:ViewBase xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TinyMvvmSample.Views"
                xmlns:vm="clr-namespace:TinyMvvmSample.Core.ViewModels;assembly=TinyMvvmSample.Core"
             x:Class="TinyMvvmSample.Views.MainView" x:TypeArguments="vm:MainViewModel">

Feedback and/or bugs

If you have feedback or find a bug in TinyMvvm, please create an issue on GitHub, https://github.com/TinyStuff/TinyMvvm/issues.

Contribute

You are very welcome to contribute to TinyMvvm. If you want to add a new feature we would like if you create an issue first so we can discuss the feature before you spend the time to implement it.

Store user data in an secure way

In many apps you want to store user data locally on the device, it could, for example, be passwords, credit card numbers etc. Even if the storage is sandboxed to your apps, you don't want to store it in clear text, you want to store it encrypted.

I have used Xamarin.Auth for many apps while it has an AccountStore class that can be used to store user data encrypted. But while it only supports iOS and Android and needed support for UWP in an app I decided to create my own library. I also felt that I don't want to install a big library when I just wanted one a little piece of it, and furthermore, the main focus was not storing user data encrypted.

So I decided to create TinyAccountManager, it is an open source project where the source can be found on GitHub, https://github.com/dhindrik/TinyAccountManager. It works together with iOS, Android and UWP. And I will properly add support for Mac apps as well.

The easiest way to install it tou your projects is via NuGet, https://www.nuget.org/packages/TinyAccountManager/.


Install-Package TinyAccountManager

The first you need to do is to initialize the AccountManager per platform.

//iOS
TinyAccountManager.iOS.AccountManager.Initialize();
 
//Android
TinyAccountManager.Droid.AccountManager.Initialize();
 
//UWP
TinyAccountManager.UWP.AccountManager.Initialize();

Save
The only property that are required is ServiceId.

var account = new Account()
{
    ServiceId = "TinyAccountManagerSample",
    Username = "dhindrik"
};
 
account.Properties.Add("Password", "MySecretPassword");
 
await AccountMananger.Current.Save(account);

Get and Exists

It's recommended that you use Exists before Get, if you using Get and there is no matching account it will throw an exception.

Account account = null;
 
var exists = await AccountManager.Current.Exists("TinyAccountManagerSample")
 
if(exists)
  account = await AccountManager.Current.Get("TinyAccountManagerSample")
Remove
 
await AccountManager.Current.Remove("TinyAccountManagerSample")

IOC

If you want to use IOC instead of the singleton pattern, you just register the implemenation for each platform with the IAccountManager interface. If you select this way you don't have to run Initialize on each platform

iOS: iOSAccountManager

Android: AndroidAccountManager

UWP: UWPAccountManager

You can find the complete documentation on GitHub, there are also a sample project.
https://github.com/dhindrik/TinyAccountManager

TinyNavigationHelper for Xamarin.Forms

TinyNavigationHelper is a helper that I created together with Johan Karlsson for a project where I don't want to install a separate MVVM framework, but I still wanted to have an abstraction for the Navigation so that I could handle navigation in my ViewModels without having a reference to Xamarin.Forms in the ViewModels. The reason for that is that I want to have my ViewModels clean from platform specific libraries so I can use them for other platforms as well, for example, if I want to extend my application with support for WPF.

You will find the source code on GitHub and you're more than welcome to contribute and give feedback.
https://github.com/dhindrik/TinyNavigationHelper. You will also find the complete documentation on GitHub.

Installation
The easiest way to install it is via NuGet:
Install-Package TinyNavigationHelper.Forms

And for projects that not reference Xamarin.Forms:
Install-Package TinyNavigationHelper.Abstraction

Configure TinyNavigationHelper
There are three ways to configure the navigation, the two first is to register the type of the view together with a key that you define. The third way is to register all views in an assembly. What the method will do that it searching throw the assembly for classes that inherit from Page.

// Option 1: Register single views
var navigationHelper = new FormsNavigationHelper(this);
navigationHelper.RegisterView("MainView");
 
// Option 2: Register single views
var navigationHelper = new FormsNavigationHelper(this);
navigationHelper.RegisterView("MainView", typeof(MainView));
 
// Option 3: Register all views (pages) that is inherited from Page
// The class name will be the key. To use this, you need to add using System.Reflection;
var asm = typeof(App).GetTypeInfo().Assembly;
navigationHelper.RegisterViewsInAssembly(asm);

If you want to use it with dependency injection you can register FormsNavigationHelper with the INavigationHelper interface.

Use TinyNavigationHelper
You can always get the current instance of TinyNavigationHelper via the static Current property on from the NavigationHelper class.

var navigationHelper = NavigationHelper.Current;

To navigate to a view, use the NavigateToAsync method.

await navigationHelper.NavigateToAsync("MainView");
 
//With parameter
await navigationHelper.NavigateToAsync("MainView", "Parameter");

The parameter will be sent to the constructor of the view.

public class MainView
{
     public MainView(object parameter)
     {
          var data = parameter as string;
     }
}

To go back, use the BackAsync method.

await navigationHelper.BackAsync();

You can also open a modal with the OpenModalAsync method.

await navigationHelper.OpenModalAsync("MainView");
 
//open a modal with an own navigation page
await navigationHelper.OpenModalAsync("MainView", true);
 
//with parameter
await navigationHelper.OpenModalAsync("MainView", "parameter", true);

You will close the modal with the CloseModalAsync method.

await navigationHelper.CloseModalAsync();

If you want to reset the navgation stack, you can use the SetRootView method.

//without parameter and navigation stack
navigationHelper.SetRootView("MainView");
 
//with parameter, but without navigation stack
navigationHelper.SetRootView("MainView", "parameter");
 
//without parameter, but with navigation stack
navigationHelper.SetRootView("MainView", true);
 
//with parameter and navigation stack
navigationHelper.SetRootView("MainView", "parameter", true);