Fix common binding errors with MVVM Light on Xamarin
There isn’t much documentation available for MVVM Light
when it comes to Xamarin.Android and Xamarin.iOS. There are several overloads for the SetBinding
method and using the wrong overload causes TargetInvocationException
or TargetException
like this one
. It’s also possible that your bindings don’t update anymore after you set one binding using an incorrect syntax.
Correct binding
You can only bind on properties, not on fields. You can use the new C# 6 syntax if you like (public TextView TextView => ...
). They don’t always have to be public
but it sure helps making them public
either way. The easiest way to create a new view property on Android is with the mvvmdroidelement
snippet provided by this extension
.
You should put your bindings in your views and make sure to respect the lifecycle of the platform you’re using. Also, always keep a reference to your binding so it doesn’t get garbage collected. I usually Store a list with all my bindings in my view.
Android activities
First create your layout in the OnCreate
method, create and store the bindings and activate/update the view model if necessary. Call Detach()
on every binding in the OnDestroy
method.
Android fragments
The layout can be set up in OnCreateView
. Use the OnViewCreated
method to set and store the bindings and activate/update the view model if necessary. Call Detach()
on every binding in the OnDestroy
method.
iOS ViewControllers
Initialize everything in the ViewDidLoad
method. Then use the ViewWillAppear
method to set and store the bindings. In some rare cases it helps calling ForceUpdateValueFromSourceToTarget
in ViewDidAppear
. Bindings should be detached using Detach()
on the binding in ViewWillDisappear
. You can use DidReceiveMemoryWarning
to clean up or dispose some references.
Static view models
To avoid the mentioned TargetException
, I’d recommend setting up a static view model locator as Laurent Bugnion explained
and using the view models on that locator. Injecting a view model in your view to bind on, usually causes the TargetException
, so try to use the view models defined in the locator.
Is the source of your binding a property in your view?
Then use this one:
1this.SetBinding(() => Path.To.Property.On.Your.View, App.Locator.MyViewModel, () => App.Locator.MyViewModel.Path.To.Property.On.Your.ViewModel, BindingMode.OneWay)
Is the source of your binding a property in your view model?
Then use the following overload:
1App.Locator.MyViewModel.SetBinding(() => App.Locator.MyViewModel.Path.To.Property.On.Your.ViewModel, this, () => Path.To.Property.On.Your.View, BindingMode.OneWay);
Two-way binding
1this.SetBinding(() => Path.To.Property.On.Your.View, App.Locator.MyViewModel, () => App.Locator.MyViewModel.Path.To.Property.On.Your.ViewModel, BindingMode.TwoWay);
Binding to a target type different from the source type
1App.Locator.MyViewModel.SetBinding(() => App.Locator.MyViewModel.Path.To.Property.On.Your.ViewModel, this, () => Path.To.Property.On.Your.View, BindingMode.OneWay).ConvertSourceToTarget(ConversionMethod);
You can also use a lambda, but that’s harder to debug.
Just binding to a source and updating the view yourself
1App.Locator.MyViewModel.SetBinding(() => App.Locator.MyViewModel.Path.To.Property.On.Your.ViewModel).WhenSourceChanges(MyUpdateMethod);
I guess this should cover all cases. I wrote this post using MVVM Light v5.2, but v5.3 or v6 is in the works (probably to be released at Xamarin Evolve 2016), so your mileage may vary with these newer versions.
You might also like
If you liked this article, follow me on LinkedIn or other social media to stay up-to-date with my latest posts. You might also like the following 2 posts about related topics:
Dependency injection with Autofac and MVVM Light in Xamarin
You gotta have MVVM A developer and his tools are inseparable. We all like SOLID and every (.NET) developer has his or her favourite dependency injection tool. There is a lot to choose from. I like Autofac because of the way it handles modules, the lifetime of a type and how it registers types.
Queue for MessageDialog in Windows RT
When I write Windows Store applications, I use MessageDialog a lot. It’s the easiest way to show a quick informative pop-up message or a question to the user. However, when you tend to use this quite often, you’ll probably run into a problem. The Windows Runtime framework doesn’t allow you to stack MessageDialogs, queue them etc.