-
Xamarin Forms for Windows Phone devs – Dependency injection with MVVM Light
In the previous post we’ve seen how Xamarin Forms offers an easy way to manage dependency injection, so that you can support the different ways how some features are managed on every platform. This way, you can use a common interface in your shared project and then have three different concrete implementation of that interface, one for each platform. In the previous sample we’ve used a PopupService, which is a class that is used to display a popup to the user by taking advantage of the specific APIs offered for each platform.
In this post, we’re going to see how to combine this approach in a MVVM project created using MVVM Light.
One project, two dependency injection’s containers
When we talked about how to create a Xamarin Forms project using MVVM Light, we’ve seen that the toolkit created by Laurent Bugnion offers a dependency injection’s container called SimpleIoC. Using a dependency container in a MVVM application is very useful, because it makes much easier to switch the implementation of a class we want to use in a ViewModel. In the previous post, we’ve seen that we are able to easily achieve this goal by using a code similar to the following one:
public MainViewModel() { IPopupService popupService = container.Resolve<IPopupService>(); popupService.ShowPopup("Sample title", "Sample message"); }
However, this code still requires you to go in each class and manually get a reference to the concrete implementation by using the container (in this sample, we’re using Unity as dependency injection library, so we use the **Resolve
()** method of the **UnityContainer** class. Thanks to dependency injection, there’s a smarter way to do this: by registering both the ViewModel and the service in the container, like in the following sample.
public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<IPopupService, PopupService>(); SimpleIoc.Default.Register<MainViewModel>(); } /// <summary> /// Gets the Main property. /// </summary> [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } }
As you can see, in the ViewModelLocator definition we’ve registered not only the MainViewModel (like we did in the previous post) but also the PopupService class, which is connected to the IPopupService interface. Thanks to this code, now we are able to get a reference to the PopupService class simply by adding an IPopupService paramter in the ViewModel’s constructor, like in the following sample:
public class MainViewModel : ViewModelBase { private readonly IPopupService _popupService; public MainViewModel(IPopupService popupService) { _popupService = popupService; } }
The dependency injection mechanism will take care of automatically injecting, into the IPopupService paramater, the concrete implementation (the PopupService) class we’ve registered in the container in the ViewModelLocator.
How to combine the two approaches
However, in the previous post, we’ve seen that Xamarin Forms offers another approach to manage dependency injection: by decorating the concrete implementation of the interface (in our case, the PopupService class) with an attribute, that allows us to use a single interface in our shared project and have three different implementations in each platform’s specific project. This way, we can deal with the fact that some features are in common across every platform (like displaying a popup or geo localizing the user) but they are implemented with different APIs and approaches.
How can we combine this approach with the standard one, so that we take the best of both worlds? Our goal is to have the MVVM Light container to automatically inject, in every ViewModel, the specific PopupService implementation we’ve included into every platform’s specific project. It’s easy, thanks to a feature offered basically by each dependency injection’s library, which is a method to register a specific instance of a class into the container. This way, when we need a concrete implementation of a class, the container will return us that specific instance, instead of creating a new one on the fly.
The following code shows how we can achieve our goal by combining the code we’ve seen in this post and in the previous one:
public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); IPopupService popupService = DependencyService.Get<IPopupService>(); SimpleIoc.Default.Register<IPopupService>(() => popupService); SimpleIoc.Default.Register<MainViewModel>(); } /// <summary> /// Gets the Main property. /// </summary> [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } }
Unlike in the previous sample, where we generically registered the PopupService class for the IPopupService interface, in this case we register a specific instance, which we have retrieved using the DependencyService class offered by Xamarin Forms. This way, we make sure that the IPopupService object we get in return is the specific implementation for the platform where the app is running. Then, we proceed to register this instance in the SimpleIoc container, by passing it as parameter of the **Register
()** method. That’s all: now, in our MainViewModel, the container will automatically inject, into the constructor’s parameter, the proper implementation for the current platform.
Wrapping up
In this post we’ve seen how to combine a standard dependency injection approach (which is useful to manage the ViewModel dependencies) with the Xamarin Forms one (which is useful to manage platform specific implementations of the same feature). You can play with a working sample by downloading the source code published on GitHub: https://github.com/qmatteoq/XamarinFormsSamples
in
-
Xamarin Forms for Windows Phone devs – Dependency injection
If you’re already worked with Windows Phone and Windows Store applications and, especially, with the MVVM pattern, you should be familiar with the dependency injection concept. In a typical application, when you need to use a class, you simply create a new instance, like in the following sample:
private void OnButtonClicked(object sender, EventArgs e) { PopupService popupService = new PopupService(); popupService.ShowPopup("Sample title", "Sample message"); }
This way, objects are created at compile time. However, when you work with the MVVM pattern, this approach has a downside. Let’s say that you’re using the PopupService in multiple classes (like ViewModels) and, suddenly, you need to change his implementation with a new one. With the previous approach, you are forced to go in each class where you use the PopupService and change the implementation with the new one.
With the dependency injection approach, instead, objects are registered inside a container, which is a special class that takes care of dispatching the objects when they’re required. Typically, with this approach, every class is described by an interface. For example, the PopupService class can be described with an interface called IPopupService, like in the following sample:
public interface IPopupService { void ShowPopup(string title, string message); }
Then, when the application starts, we specify for each interface which is the concrete implementation we want to use in the application, like in the following code (keep in mind that it’s just a sample, there are multiple libraries to implement dependency injection, each of them with its APIs and methods):
public App() { IUnityContainer container = new UnityContainer(); container.RegisterType<IPopupService, PopupService>(); }
In the end, whenever a class needs to use a PopupService object, instead of simply creating a new instance, it asks to the container to return the registered one, like in the following sample:
private void OnButtonClicked(object sender, EventArgs e) { IPopupService popupService = container.Resolve<IPopupService>(); popupService.ShowPopup("Sample title", "Sample message"); }
The advantage of this approach should be clear: whenever we need to change the implementation of the IPopupService interface, it’s enough to change the concrete implementation of the interface that is registered in the container, like:
public App() { IUnityContainer container = new UnityContainer(); container.RegisterType<IPopupService, FakePopupService>(); }
Automatically, all the classes that are using the PopupService class will immediately start to use the new implementation, called FakePopupService, simply by changing one line of code.
###
Dependency injection and Xamarin Forms
Dependency injection becomes very useful when you work with Xamarin Forms: the purpose of this technology is to allow developers to share as much code as possible between the three different mobile platforms (iOS, Android and Windows Phone). The Xamarin technology was created with this purpose in mind, however Xamarin Forms takes this approach to the next level, by allowing developers to share not just business logic, but also the user interface. Xamarin Forms, in fact, uses a XAML based approach: the user interface is defined using XML, where each control is identified by a specific XML tag. The biggest difference with the standard XAML (which is supported only by Microsoft technologies, like Windows Phone or WPF) is that the controls are automatically translated into the native platform controls. This way, unlike with cross platform applications based on web technologies (which offer the same UI on all the platforms), we’ll be able to keep the UI consistent with the guidelines and the user interface of the platform.
However, there are some scenarios which simply don’t fit the shared code approach. We can’t forget, in fact, that Xamarin, unlike web technologies, doesn’t provide a way to create the application just once and run it everywhere: one of the biggest pros of Xamarin, in fact, is that it allows developers to make use of every platform specific feature, unlike web applications that typically support only the features that are in common between every platform. Consequently, you still need to learn how Android and iOS development work if you want to create a real application. However, thanks to Xamarin, you won’t have to learn also a new language in the process: Xamarin, in fact, offers a way to use the native APIs with the familiar C# syntax.
The same applies for Xamarin Forms: it offers a way to share not just business logic but also user interface code but, in the end, we still need to deal with the specific platform features and implementations. Let’s say, for example, that we want to add the PopupService class we’ve previously seen in our Xamarin Forms project, which offers a ShowPopup() method that displays an alert to the user. Each platform has a different way to display a popup message: for example, in Windows Phone you use the MessageBox class; on Android, you have the AlertDialog class; on iOS, instead, you use the UIAlertView class. However, we would love to have a way to use the ShowPopup() method in our shared page and, automatically, see it rendered on each platform with its specific code.
Thanks to the dependency injection approach, we can: in the shared page we’re going to get a reference to the IPopupService class and to use the ShowPopup() method. At runtime, the dependency container will inject into the IPopupService object the specific implementation for the platform. However, compared to a regular dependency injection approach (like the one we’ve previously seen), there are some differences when we need to use it in Xamarin Forms.
Please note: the sample we’re going to see has been created just for demonstration purposes. Xamarin Forms, in fact, already offers a way to display popups to the user in a shared page, without having to deal with the different implementations for each platform.
One interface, multiple implementations
The first step is to create a common interface in the shared project, since it will be unique for each platform:
public interface IPopupService { void ShowPopup(string title, string message); }
Then we need a concrete implementation of this interface, one for each platform: we’re going to create in every specific platform project this time. For example, here is how it looks like the implementation in the Windows Phone project:
public class PopupService: IPopupService { public void ShowPopup(string title, string message) { MessageBox.Show(message, title, MessageBoxButton.OK); } }
Here is, instead, how it looks like in the Android project:
public class PopupService: IPopupService { public void ShowPopup(string title, string message) { AlertDialog.Builder alert = new AlertDialog.Builder(Forms.Context); alert.SetTitle(title) .SetMessage(message) .SetPositiveButton("Ok", (sender, args) => { Debug.WriteLine("Ok clicked"); }) .Show(); } }
The next step is to understand how to use the proper implementation for each platform. In our shared code, we’re going to simply use the interface, like in the following sample:
private void OnButtonClicked(object sender, EventArgs e) { IPopupService popupService = new PopupService(); popupService.ShowPopup("Sample title", "Sample message"); }
However, this code won’t simply work: we don’t have a single implementation of the PopupService class, but three different implementations, each of them with its namespace. Also the previous dependency injection approach we’ve seen doesn’t solve our problem: when we register the implementation in the container, we still need to specify which is the concrete class to use and, in our scenario, we have three of them.
Luckily, Xamarin Forms offers a smart approach to solve this situation: instead of manually registering the implementations into a container, we decorated the classes with an attribute. At runtime, automatically, Xamarin Forms will detect which is the interface connected to the implementation and will return to the application the proper object. To make it working, it’s enough to add the following attribute each concrete implementation of the class:
using System.Windows; using DependencySample.Services; using DependencySample.WinPhone.Services; [assembly: Xamarin.Forms.Dependency(typeof(PopupService))] namespace DependencySample.WinPhone.Services { public class PopupService: IPopupService { public void ShowPopup(string title, string message) { MessageBox.Show(message, title, MessageBoxButton.OK); } } }
The only variable part of the attribute is the parameter of the Dependency class: we need to specify the type of the current class (in our sample, it’s PopupService). Then, in our shared project, when we need to use the PopupService, we’re going to retrieve it using a Xamarin Forms class called DependencyService, like in the following sample:
private void OnButtonClicked(object sender, EventArgs e) { IPopupService popupService = DependencyService.Get<IPopupService>(); popupService.ShowPopup("Sample title", "Sample message"); }
We use the **Get
** method, where **T** is the interface of the class we want to use. Automatically, Xamarin Forms will analyze the registered DLLs in the project and will return the concrete implementation that is available in the platform’s specific project. ###
Wrapping up
In this post we’ve seen how to use the native dependency container that Xamarin Forms offers to developers. In the next post, we’ll see how to combine it with a traditional dependency injection approach, which comes useful when you’re developing a Xamarin Forms app using MVVM. You can download the sample project used in this post on GitHub: https://github.com/qmatteoq/XamarinFormsSamples
in
-
Xamarin Forms for Windows Phone devs – Using the MVVM pattern
We’ve already talked many times about the MVVM pattern on this blog and how to implement it in Windows Phone 8 apps using Caliburn Micro or in Universal Windows apps with Caliburn Micro and Prism. The Model-View-ViewModel pattern is very useful in XAML based projects, because the separation between logic and user interface gives many advantages in testability and maintainability. However, when we’re dealing with projects that target multiple platforms with a shared code base (like with Universal Windows apps), using the MVVM pattern is, more or less, a basic requirement: thanks to the separation between logic and user interface, it becomes easier to share a good amount of code with the different projects.
Xamarin Forms makes no exceptions: applying the MVVM pattern is the best way to create a common codebase that can be shared among the iOS, Android and Windows Phone projects. In this post, we’ll see how to create a simple project using one of the most popular toolkits out there: MVVM Light.
Why MVVM Light?
MVVM Light is, for sure, the most simple and flexible MVVM toolkit available right now. It’s main advantage is simplicity: since it’s implementation is very basic, it can be easily ported from one platform to another. As you’re going to see in this post, if you have already worked with MVVM Light on other platforms, you’ll find yourself at home: except for some minor difference, the approach is exactly the same you would use in Windows Phone, Windows Store or WPF.
However, the MVVM Light simplicity is also its weak point: compared to frameworks like Caliburn Micro or Prism, it misses all the infrastructure that is often required when you have to deal with platform specific features, like navigation, application lifecycle, etc. Consequently, as we’re going to see in the next posts, you may have the need to extend MVVM Light, in order to solve platform specific scenarios. In the next post I will show you the implementation I did to solve these problem: for now, let’s just focus on implementing a basic Xamarin Forms project with MVVM Light. This knowledge, in fact, it’s important to understand the next posts I’m going to publish.
Creating the first MVVM project
The first step is the same we’ve seen in a previous post: creating a new Xamarin.Forms Blank App. After we’ve checked that we’re using the latest Xamarin Forms version, we need to install also MVVM Light in the shared project: you’ll need to install the specific version for PCL libraries, which is http://www.nuget.org/packages/Portable.MvvmLightLibs/
Now you’re ready to set up the infrastructure to create the application: let’s start by adding our first View and our first ViewModel. It’s not required, but to better design the application I prefer to create a folder for the views (called Views) and a folder for the ViewModels (called ViewModels). Then add a new Xamarin Forms page into the Views folder (called, for example, MainView.xaml) and a new simple class into the ViewModels folder (called, for example, MainViewModel.cs).
The ViewModelLocator
One of the basic requirements in a MVVM application is to find a way to connect a View to its ViewModel: we could simply create a new instance of the ViewModel and assign it as data context of the page, but this way we won’t be able to use techniques like dependency injection to resolve ViewModels and the required services at runtime (we’ll talk again about this approach in the next post). The typical approach when you work with MVVM Light is to create a class called ViewModelLocator, which takes care of passing to every View the proper ViewModel. Here is how the ViewModelLocator class looks like in a Xamarin Forms project:
public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<MainViewModel>(); } /// <summary> /// Gets the Main property. /// </summary> [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } }
When the class is created, we register the default dependency injection provider we want to use: in this case, we use the native one offered by MVVM Light, called SimpleIoc. Then, we register in the container, by using the **Register
()** method, all the ViewModels and services we want to use. In this sample, we won’t use any service: we’ll see in the next post how to manage them; so we just register our **MainViewModel** in the container. The next step is to create a property that will be used by the View to request the proper ViewModel instance: we use again the dependency injection container, in this case to get a registered class, by using the **GetInstance ()** method (where **T** is the object’s type we need). Now we can use the ViewModelLocator to assing a ViewModel to its View: in our case, the MainView should be connected to the MainViewModel. In a Windows Phone app, this goal is typically achieved by declaring the ViewModelLocator as a global resource in the App class and then, in the XAML, assigning the proper property (in this case, Main) to the DataContext property of the page. This way, the ViewModel will be assigned as DataContext of the entire page and every nested control will be able to access to the commands and properties that are exposed by the ViewModel.
However, this approach doesn’t work in Xamarin Forms, since we don’t have the concept of global resources: we don’t have an App.xaml file, where to declare resources that are shared across every page of the application. The easiest way to solve this problem is to declare the ViewModelLocator as a static property of the App class in the Xamarin Forms shared project, like in the following sample:
public class App: Application { public App() { this.MainPage = new MainView(); } private static ViewModelLocator _locator; public static ViewModelLocator Locator { get { return _locator ?? (_locator = new ViewModelLocator()); } } }
This way, you’ll be able to connect the ViewModel to the View by using this static property in the code behind file of the page (in our case, the file MainView.xaml.cs):
public partial class MainView { public MainView() { InitializeComponent(); this.BindingContext = App.Locator.Main; } }
You can notice one of the most important differences between the XAML in Windows Phone and the XAML in Xamarin Forms: the DataContext property is called BindingContext. However, its purpose is exactly the same: define the context of a control.
###
Define the ViewModel
Creating a ViewModel it’s easy if you’ve already worked with MVVM Light, since the basic concepts are exactly the same. Let’s say that we want to create a simple applications where the user can insert his name: by pressing a button, the page will display a message to say hello to the user. Here is how the ViewModel to manage this scenario looks like:
public class MainViewModel: ViewModelBase { private string _name; public string Name { get { return _name; } set { Set(ref _name, value); ShowMessageCommand.RaiseCanExecuteChanged(); } } private string _message; public string Message { get { return _message;} set { Set(ref _message, value); } } private RelayCommand _showMessageCommand; public RelayCommand ShowMessageCommand { get { if (_showMessageCommand == null) { _showMessageCommand = new RelayCommand(() => { Message = string.Format("Hello {0}", Name); }, () => !string.IsNullOrEmpty(Name)); } return _showMessageCommand; } } }
You can see, in action, all the standard features of a ViewModel created using MVVM Light as a toolkit:
- The ViewModel inherits from the ViewModelBase class, which gives you some helpers to properly support the INotifyPropertyChanged interface that is required to notify the controls in the View when the properties that are connected through binding are changed.
- Every property isn’t defined with the standard get – set approach but, when the value of the property changes (in the set method), we call the Set() method offered by MVVM Light which, other than just assigning the value to the property, takes care of dispatching the notification to the controls in the View.
- When you work with the MVVM pattern, you can’t react to user’s actions using event handlers, since they have a strict dependency with code behind: you can’t declare an event handler inside another class. The solution is to use commands, which are a way to express actions with a property, that can be connected to the View using binding. MVVM Light offers a class that makes this scenario easier to implement, called RelayCommand. When you create a RelayCommand object, you need to set: 1) the action to perform (in our case, we define the message to display to the user) 2) optionally, the condition that needs to be satisfied for the command to be activated (in our case, the user will be able to invoke the command only if the property called Name isn’t empty). If the condition isn’t met, the control be automatically disabled. In our sample, if the user didn’t insert his name in the box, the button will be disabled.
- When the value of the Name property changes, we also call the RaiseCanExecuteChanged() method offered by the RelayCommand we’ve just defined: this way, every time the Name property changes, we tell to the command to evaluate its status, since it could be changed.</ul> ###
The View
The following code, instead, show the Xamarin Forms XAML page that is connected to the ViewModel we’ve previously seen:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MvvmLight_Sample.Views.MainView"> <StackLayout Padding="12, 0, 12, 0"> <Label Text="Insert your name:" /> <Entry Text="{Binding Path=Name, Mode=TwoWay}" /> <Button Command="{Binding Path=ShowMessageCommand}" Text="Show message" /> <Label Text="{Binding Path=Message}" FontSize="30" /> </StackLayout> </ContentPage>
- When you work with the MVVM pattern, you can’t react to user’s actions using event handlers, since they have a strict dependency with code behind: you can’t declare an event handler inside another class. The solution is to use commands, which are a way to express actions with a property, that can be connected to the View using binding. MVVM Light offers a class that makes this scenario easier to implement, called RelayCommand. When you create a RelayCommand object, you need to set: 1) the action to perform (in our case, we define the message to display to the user) 2) optionally, the condition that needs to be satisfied for the command to be activated (in our case, the user will be able to invoke the command only if the property called Name isn’t empty). If the condition isn’t met, the control be automatically disabled. In our sample, if the user didn’t insert his name in the box, the button will be disabled.
- Every property isn’t defined with the standard get – set approach but, when the value of the property changes (in the set method), we call the Set() method offered by MVVM Light which, other than just assigning the value to the property, takes care of dispatching the notification to the controls in the View.
</pre>
It’s a simple form, made by a text area where the user can insert his name and a button that, when it’s pressed, displays the message using a label. You can notice some difference with the standard XAML available in Windows Phone: * <div align="left"> The <strong>StackPanel</strong> control, which is able to display the nested controls one below the other, is called <strong>StackLayout</strong>. </div> * <div align="left"> To define the distance of the control from the screen’s border, we use the <strong>Padding</strong> property instead of the <strong>Margin</strong> one. </div> * The **TextBlock** control, used to display a text to the user, is called **Label**. * The **TextBox** control, used to receive the input from the user, is called **Entry.** * The content of the button (in this case, a text) is set using the **Text** property, while in the standard XAML is called **Content** and it accepts also a more complex XAML layout. Except for these differences in the XAML definition, we’re using standard binding to connect the controls with the properties defined in the ViewModel: * The **Entry** control has a property called **Text**, which contains the name inserted by the user: we connect it to the **Name** property of the ViewModel, using the two-way binding. * The **Button** control has a property called **Command**, which is connected to the **ShowMessageCommand** we’ve defined in the ViewModel. This way, the button will be enabled only if the **Name** property isn’t empty; if it’s enable, by pressing it we’ll display the hello message to the user. * The hello message is stored into the **Message** property of the ViewModel, which is connected using binding to the last **Label** control in the page. ### Wrapping up In this post we’ve seen the basic concepts of using MVVM Light in a Xamarin Forms: except for some differences (like the **ViewModelLocator** usage), the approach should be very familiar to any Windows Phone developer that has already worked with the MVVM pattern and the MVVM Light toolkit. In the next posts we’ll take a look at how the dependency injection approach works in Xamarin Forms and how we can leverage it in a MVVM Light project. As usual, you can find the sample code used in this post on GitHub at [https://github.com/qmatteoq/XamarinFormsSamples](https://github.com/qmatteoq/XamarinFormsSamples "https://github.com/qmatteoq/XamarinFormsSamples")
in
- The ViewModel inherits from the ViewModelBase class, which gives you some helpers to properly support the INotifyPropertyChanged interface that is required to notify the controls in the View when the properties that are connected through binding are changed.
subscribe via RSS