Indexed ViewModelLocator With MVVMLight And Xamarin Forms
Working with MVVMLight toolkit and Xamarin Forms removes a lot of boiler plate coding. When it comes to the basic of resolving viewmodels this clean code gets a bit blurry, so let's see how we can improve this.
The default Viewmodel resolving
Building a solution with MVVMLight, the most common solution to resolve viewmodels is a mix of SimpleIOC and a ViewModelLocator. The ViewModelLocator provides basic binding for each ViewModel it exposes and Views consume the ViewModels by databinding.
The code above ensures that the BindingContext in the view is set by the CarVM binding where CarVM is the name of the binding in the ViewModelLocator providing the CarViewModel. As the solution grows, the ViewModelLocator becomes a class with a lot of basic getter’s just to resolve ViewModels, some pretty trivial code to write an maintain.
If we start by taking a look at the XAML code in the view, we currently have the Binding CarVM as a hard databinding to a specific property on the ViewModelLocator. Luckily we have the option to use an indexed binding, where we can specify a simple name as a string, we want to bind to and not a specific property. This means we can take advantage of a single index on the viewmodel to resolve viewmodels and less code to maintain! The flow is illustrated below.
The first thing we need to do is change the binding in the view to make use of the indexer. As you can see I’ve also changed the name of the index to CarViewModel. this is because we want to use the binding index as type lookup in the ViewModelLocator later meaning the name should match a corresponding type.
The refactor of our ViewModelLocator introduces some new concepts. As specified by the view, we should provide an indexer. The indexer is added by letting the ViewModelLocator inherit from DynamicObject. This makes TryGetMember available, which the binding in the view will target. Combined with this, we add an indexer which use the final piece of the puzzle, the ViewModelResolver.
The responsibility of the ViewModelResolver is to resolve an instance of a ViewModel, from a name specifying its type. One thing to keep in mind, the ViewModelResolver is located inside a PCL. This is necessary to know when we resolve the type from the assembly. We find all the types defined and make a match on the provided name. When located, the instance is resolved and all dependencies it might might require (constructor based) will also be resolved, when using the DI Container.
With the ViewModelResolver in place we can now run the project and if we extend the app with more view and viewmodels, we just need to ensure everything is registered in the DI container. If another DI container like Autofac is used instead, it can simply be injected into the ViewModelResolver.
The complete source code is available here GitHub Repository.comments powered by Disqus