Xamarin.Forms Tips and Tricks

07/02/2020

Data ostatniej aktualizacji: 06.08.2020 05:11

I started developing with Xamarin in late 2018, when we at Altkom decided to rewrite ONSTAGE in Xamarin.Forms 3.x for to gain some understanding regarding the platform and its potential. We’re quite satisfied with the results! We implemented a fully cross-platform UI with no (sic!) custom renderers – here’s an article about it written by Maciej Gos, our Lead .NET Developer. You can find the released product in Play Store.

This article compiles our most valuable findings, tips and tricks that we discovered during the development of ONSTAGE as well as our Insurance Sales PoC.

1. MVVM Framework woes

When it comes to MVVM frameworks, there’s loads of options available. Which one should you choose then? The rule of thumb for us seems to be to use the simplest solution.
We needed a base ViewModel (like an implementation of INotifyPropertyChanged) to build upon. No additional bells and whistles – we like the new Shell navigation a lot, so let’s use it again. Thus, throughout both our PoCs and commercial projects we swear by James Montemagno’s MVVMHelpers.
James is a prominent Xamarin whiz and his libraries proved themselves worthy of recommendation many times over.

The other choice (which we tested and can recommend as an alternative) would be the Prism library. It does much more than just providing boilerplate for common development workflows (e.g. it supports different DI/IoC libraries and implements its own navigation) but is modular, so you can choose what you want to use. It’s also pretty popular with the Xamarin community.

If you have a favourite MVVM framework, don’t hesitate to write about it in the comments! We’re always looking for new (preferably better) solutions.

2. Tip: Simplifying access to the ViewModel

This one is pretty simple. In your base Page class, try using something similar to the snippet below:

protected virtual T ViewModel => BindingContext as T;

Now you don’t have to cast your BindingContext e.g. in event handler methods. The virtual keyword not only makes the call lazy, but also overridable.
You can see our example implementation of the base Page class here.

3. Tip: Compile-time bindings

This trick is a pretty recent discovery of mine, but it’s really useful! Not only it’s a speed boost, it’s also helps avoid hard-to-debug mistakes that make your app blow up in runtime.

See a comprehensive article about it here.

4. Tip: Navigating large ViewModels

When developing a commercial app, the ViewModels have a natural tendency to reach the size of a grown homo sapiens specimen. Fortunately we have some tools to alleviate at least some of that pain.

An example solution in a normal .NET project would be to split the class into smaller, more specialised classes… but we can’t really do that here. A ViewModel is also a BindingContext, and we only get one per View/Page.
The first thing I always do is to categorise members of a class into #regions. This makes Visual Studio create custom outlines on the left side of the gutter which we can expand and collapse at will.
Here’s an example from our Insurance Sales PoC.

Other thing you’ll probably notice is the unusual grouping of properties.

private string _username;
public string Username { get => _username; set => SetProperty(ref _username, value); }

Conventionally you’d group the private members in a block of their own, same with public and so on.
In Xamarin ViewModels, I stick to grouping properties a bit differently because of their behaviour – for every property we actually need two members, a private one containing the value and the public one that acts as a proxy while also raising the OnPropertyChanged event. I found myself losing focus every time I had to scroll between the members, so eventually I started just grouping them together instead. Saves a lot of trouble and feels more sane to me.
I recently found James Montemagno does a very similar thing, so I guess I wasn’t the only one with that problem

Additionally, C# allows us to split a class using the partial keyword. This way, we don’t over-engineer the code – we only separate the parts of a class into dedicated files.
I almost never use it personally, but I have seen it used in production code and it’s good to know it exists.

5. DI/IoC woes

If you come from an enterprise background, you’re probably used to having a DI/IoC container library in a solution. Nowadays, you probably have one built-in with your framework.
Thing is, with Xamarin you want to cut down on the libraries. Seriously. I don’t necessarily mean performance – although that’s also very important, especially in mobile development. Some libraries don’t play nice with Android linkers. And trust me, you do not want to get into the rabbit hole of finding out which library should be excluded from linking.

The Xamarin-specific libraries use the built-in DependencyService so it makes sense to use it instead of importing an additional one just for dev convenience. Our needs are pretty basic anyway.

One gripe I had with DependencyService is that you can’t just ask for dependencies in the constructor like you’re probably used to do:

public ExampleViewModel(
IAuthenticationService authenticationService,
IExampleService exampleService
) : base(authenticationService)
{
 _exampleService = exampleService;
}

But yet again, C# comes to the rescue. If we add this() (see docs) we get the following:

public ExampleViewModel() : this(
DependencyService.Resolve<IAuthenticationService>(),
DependencyService.Resolve<IExampleService>()
) { }

Yup, it’s that simple. By reusing the existing constructor, we get DRY code that doesn’t require us to maintain two constructors with similar or repeating logic. This also allows us to test the ExampleViewModel using our good old mocks without any additional haberdashery.

6. Tip: Debugging (mainly, but not exclusively) on Android

One of the choke points of Xamarin development in general is debugging. If you ever tried to debug without a stacktrace, you know what I mean.
Fortunately there are a few ways to prevent your brain from melting.

First off, try putting a try/catch clause inside the App constructor in your App.xaml.cs. If you did your error handling right, the exception should be captured along with a full stacktrace.

Afterwards, enable debugging in the AssemblyInfo.cs of the Android project like so:

#if DEBUG
 [assembly: Application(Debuggable = true)]
#else
 [assembly: Application(Debuggable = false)]
#endif

Finally, use the Android Device Log window in VS (don’t forget to select your emulator device and filter the log by mono) to find out what exactly blew up and where. Hopefully it’ll help!

7. Development experience – Windows vs. macOS

If you’re wondering which OS is it easier to develop on, we’d have to veer towards macOS. The reason is pretty simple. Compared to Windows, we almost always get full stacktraces.
Although we didn’t do any comprehensive performance benchmarks, developing on macOS felt faster.

Summary

I hope you learned something from the tips and tricks above. I wish you a great and productive adventure with Xamarin! We at Altkom are pretty satisfied with it. Tooling and IDE support is constantly getting better. There’s a growing number of production apps created with it, which bodes well for the future of the framework.

Bartosz Jędrecki, Developer .NET w Altkom Software & Consulting