Tuesday, 29 December 2015

Prism for Xamarin.Forms 6.2

In early December, Brian Lagunas announced a pre-release of Prism for Xamarin.Forms 6.2.0. Over Christmas I checked it out and here’s what I found out.

The big changes are around bootstrapping and navigation, with simplification and new features being the order of the day. There are also some breaking changes, in that INavigationPageProvider and NavigationPageProviderAttribute have both been removed as they are no longer needed due to the INavigationService handling the majority of navigation scenarios now.

Bootstrapping

The CreateMainPage and InitializeShell methods are now deprecated, with the OnInitialized override now being used to navigate to the initial page of the app:

1 public class Bootstrapper : UnityBootstrapper 2 { 3 protected override void RegisterTypes() 4 { 5 Container.RegisterTypeForNavigation<HomePage>(); 6 } 7 8 protected override void OnInitialized() 9 { 10 NavigationService.Navigate("HomePage"); 11 } 12 }

The page being navigated to is registered in the RegisterTypes override, with navigation then being invoked from the OnInitialized override. As well as being a simpler app bootstrapping process, it also removes the problems with some navigation scenarios on startup, such as navigating to a MasterDetailPage and then changing the Detail page,.

Navigation

The INavigationService now supports a number of new features, including passing parameters via the GoBack method, support for URI-based navigation, and deep linking. For information about the new navigation features see Brian’s blog post.

The INavigationService now detects the type type of page being navigated from, and handles the navigation for you. For example, it will detect that navigation is originating from a MasterDetailPage and will set the MasterDetailPage.Detail property to the navigation target, instead of pushing a new page onto the navigation stack.

In addition, the INavigationService supports more complex navigation scenarios. For example, imagine that you want your app to navigate to a MasterDetailPage that sets the Detail page to a NavigationPage, and then displays a ContentPage. As with all Prism-based apps, the pages must first be registered with the navigation service:

1 protected override void RegisterTypes() 2 { 3 Container.RegisterTypeForNavigation<HomePage>(); 4 Container.RegisterTypeForNavigation<MyNavigationPage>(); 5 Container.RegisterTypeForNavigation<MyMasterDetailPage>(); 6 Container.RegisterTypeForNavigation<WeekPage>(); 7 Container.RegisterTypeForNavigation<MonthPage>(); 8 Container.RegisterTypeForNavigation<YearPage>(); 9 }

After registering the pages, it then becomes possible to perform the required navigation in one call:

1 NavigationService.Navigate("MyMasterDetailPage/MyNavigationPage/MonthPage");

The result of the navigation will show a MasterDetailPage whose Detail page is a NavigationPage, with the MonthPage being pushed onto the navigation stack for display. In addition, the navigation stack will be as expected, and so backwards navigation will return down the stack.

For me this is the killer feature in this release of Prism for Xamarin.Forms, as when combined with the URI-based navigation support and parameter passing, it becomes possible to launch a Xamarin.Forms app from a website and deep link to content within the app, while maintaining the correct navigation stack.

Summary

The original release of Prism for Xamarin.Forms was a welcome addition to the Prism family, and simplified the development of Xamarin.Forms apps. However, it was slightly restrictive in some areas, but with the preview release of Prism for Xamarin.Forms 6.2.0 the majority of these restrictions no longer exist.

While not everyone is a believer in using such libraries in mobile app development, Prism for Xamarin.Forms offers a clear productivity boost and simplifies the development of fully unit testable Xamarin.Forms apps that have a clean separation of concerns. Going forward I’ll certainly be using it for my own app development efforts, and I look forward to it moving from a pre-release to a stable release.

Tuesday, 22 December 2015

Accessing Image Pixel Data in a Xamarin.Forms App – WinRT

Previously, I’ve described the basic architecture for accessing and manipulating pixel data from a Xamarin.Forms project. A Xamarin.Forms PCL project defines the IBitmap interface, which specifies the operations that must be implemented in each platform-specific project to access and manipulate pixel data. I then explained the operation of the Bitmap class in the Xamarin.Forms iOS project, and the Xamarin.Forms Android project, which both implement the IBitmap interface.

In this blog post I’ll explain the operation of the Bitmap class in the Xamarin.Forms WinRT project, which also implements the IBitmap interface. The DependencyService can be used to invoke a method from the Xamarin.Forms.PCL project, which in turn invokes IBitmap operations.

Note that this WinRT pixel access implementation differs from that in a previous blog post about Accessing Image Pixel Data in a C# Windows Store App.

Disclaimer: The code featured here is alpha code, so all the usual caveats apply.

Implementation

The following code shows the Bitmap class implemented in WinRT:

1 public class Bitmap : IBitmap<Task<Stream>> 2 { 3 const byte bytesPerPixel = 4; 4 int width; 5 int height; 6 double dpiX, dpiY; 7 StorageFile photoFile; 8 byte[] pixelData; 9 10 public Bitmap(StorageFile file) 11 { 12 photoFile = file; 13 } 14 15 public void ToPixelArray() 16 { 17 throw new NotImplementedException(); 18 } 19 20 public async Task ToPixelArrayAsync() 21 { 22 var imageDataStream = await photoFile.OpenReadAsync(); 23 var decoder = await BitmapDecoder.CreateAsync(imageDataStream); 24 var frame = await decoder.GetFrameAsync(0); 25 var dataProvider = await frame.GetPixelDataAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, new BitmapTransform(), ExifOrientationMode.RespectExifOrientation, ColorManagementMode.DoNotColorManage); 26 27 width = Convert.ToInt32(decoder.PixelWidth); 28 height = Convert.ToInt32(decoder.PixelHeight); 29 dpiX = decoder.DpiX; 30 dpiY = decoder.DpiY; 31 32 pixelData = new byte[width * height * bytesPerPixel]; 33 pixelData = dataProvider.DetachPixelData(); 34 35 imageDataStream.Dispose(); 36 } 37 38 public void TransformImage(Func<byte, byte, byte, double> pixelOperation) 39 { 40 byte r, g, b; 41 42 try 43 { 44 // Pixel data order is BGRA 45 for (int i = 0; i < pixelData.Length; i += bytesPerPixel) 46 { 47 b = pixelData[i]; 48 g = pixelData[i + 1]; 49 r = pixelData[i + 2]; 50 51 // Leave alpha value intact 52 pixelData[i] = pixelData[i + 1] = pixelData[i + 2] = (byte)pixelOperation(r, g, b); 53 } 54 } 55 catch (Exception ex) 56 { 57 Debug.WriteLine(ex.Message); 58 } 59 } 60 61 public async Task<Stream> ToImage() 62 { 63 var ras = new InMemoryRandomAccessStream(); 64 var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras); 65 encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)width, (uint)height, dpiX, dpiY, pixelData); 66 await encoder.FlushAsync(); 67 pixelData = null; 68 return ras.AsStream(); 69 } 70 }

The ToPixelArrayAsync method is used to read and decode the photo, get the pixel data, and convert it to a byte array of raw pixel data. The image’s pixel data is formatted as 32 bits per pixel, with each pixel being composed of a Red, Green, Blue, and Alpha channel. Therefore, the pixelData array stores each pixel over four array elements (B, G, R, A).

The TransformImage method is used to perform an imaging operation on the pixel data, such as convert to greyscale. The method specifies a Func parameter that’s used to perform a per-pixel operation. The Func is passed from the Xamarin.Forms PCL project into the method, and operates on each pixel component. At the moment the TransformImage method is hard-coded to place the result of the Func into each pixel component. This is purely for my own test purposes, for implementing a ConvertToGreyscale Func. It can easily be modified to not duplicate the result of the Func across all four colour components.

The ToImage method is then used to place the transformed pixel data into an InMemoryRandomAccessStream that contains a JPEG encoded image.

The Bitmap class can then be invoked as follows:

1 public async Task<Stream> TransformPhotoAsync(Func<byte, byte, byte, double> pixelOperation) 2 { 3 ... 4 5 return await Task.Run(async () => 6 { 7 var bitmap = new Bitmap(PhotoFile); 8 await bitmap.ToPixelArrayAsync(); 9 bitmap.TransformImage(pixelOperation); 10 stream = await bitmap.ToImage(); 11 return stream; 12 }); 13 }

A new Bitmap instance is created, with a StorageFile being passed into the constructor. The photo is read and converted to an array of pixels, transformed by the pixelOperation Func, and then converted into JPEG image that’s returned as a Stream for display by a Xamarin.Forms Image control. All of this work is wrapped in a Task.Run in order for it to be executed on a background thread.

Summary

This blog post has described how to access and manipulate pixel data in a Xamarin.Forms WinRT project, by implementing the Bitmap class. The Bitmap class implements the IBitmap interface that’s provided by the Xamarin.Forms PCL project.

Tuesday, 15 December 2015

Accessing Image Pixel Data in a Xamarin.Forms App – Android

Previously, I’ve described a basic architecture for accessing and manipulating pixel data from a Xamarin.Forms project. A Xamarin.Forms PCL project defines the IBitmap interface, which specifies the operations that must be implemented in each platform-specific project to access and manipulate pixel data. I then explained the operation of the Bitmap class in the Xamarin.Forms.iOS project, which implements the IBitmap interface.

In this blog post I’ll explain the operation of the Bitmap class in the Xamarin.Forms Android project, which implements the IBitmap interface. The DependencyService can be used to invoke a method from the Xamarin.Forms PCL project, which in turn invokes IBitmap operations.

Disclaimer: The code featured here is alpha code, so all the usual caveats apply.

Implementation

The following code shows the Bitmap class implemented on Android:

1 public class Bitmap : IBitmap<Android.Graphics.Bitmap> 2 { 3 const byte bytesPerPixel = 4; 4 readonly int height; 5 readonly int width; 6 byte[] pixelData; 7 Android.Graphics.Bitmap bitmap; 8 string photoFile; 9 10 public Bitmap (string photo) 11 { 12 photoFile = photo; 13 var options = new BitmapFactory.Options { 14 InJustDecodeBounds = true 15 }; 16 17 // Bitmap will be null because InJustDecodeBounds = true 18 bitmap = BitmapFactory.DecodeFile (photoFile, options); 19 width = options.OutWidth; 20 height = options.OutHeight; 21 } 22 23 public void ToPixelArray () 24 { 25 bitmap = BitmapFactory.DecodeFile (photoFile); 26 27 int size = width * height * bytesPerPixel; 28 pixelData = new byte[size]; 29 var byteBuffer = Java.Nio.ByteBuffer.AllocateDirect (size); 30 bitmap.CopyPixelsToBuffer (byteBuffer); 31 Marshal.Copy (byteBuffer.GetDirectBufferAddress (), pixelData, 0, size); 32 byteBuffer.Dispose (); 33 } 34 35 public void TransformImage (Func<byte, byte, byte, double> pixelOperation) 36 { 37 byte r, g, b; 38 39 try { 40 // Pixel data order is RGBA 41 for (int i = 0; i < pixelData.Length; i += bytesPerPixel) { 42 r = pixelData [i]; 43 g = pixelData [i + 1]; 44 b = pixelData [i + 2]; 45 46 // Leave alpha value intact 47 pixelData [i] = pixelData [i + 1] = pixelData [i + 2] = (byte)pixelOperation (r, g, b); 48 } 49 } catch (Exception ex) { 50 Console.WriteLine (ex.Message); 51 } 52 } 53 54 public Android.Graphics.Bitmap ToImage () 55 { 56 var byteBuffer = Java.Nio.ByteBuffer.AllocateDirect (width * height * bytesPerPixel); 57 Marshal.Copy (pixelData, 0, byteBuffer.GetDirectBufferAddress (), width * height * bytesPerPixel); 58 bitmap.CopyPixelsFromBuffer (byteBuffer); 59 byteBuffer.Dispose (); 60 return bitmap; 61 } 62 63 public void Dispose () 64 { 65 if (bitmap != null) { 66 bitmap.Recycle (); 67 bitmap.Dispose (); 68 bitmap = null; 69 } 70 pixelData = null; 71 } 72 }

The constructor reads and decodes the photo. Setting the InJustDecodeBounds property to true while decoding avoids allocating memory for the bitmap and hence returns null for the bitmap object, but does set the OutWidth, and OutHeight properties. This technique allows you to read the dimensions and type of the image data prior to construction (and memory allocation) of the bitmap.

The ToPixelArray method is used to read the photo to a Android.Graphics.Bitmap and convert it to a byte array of raw pixel data. The image’s pixel data is placed into a continuous sequence of bytes. It’s formatted as 32 bits per pixel, with each pixel being composed of a Red, Green, Blue, and Alpha channel. It’s then copied to the pixelData array. Therefore, the pixelData array stores each pixel over four array elements (R, G, B, A). It’s likely that the pixelData array is not required, and that the pixel data can be accessed directly through the ByteBuffer instance. I’ll be exploring this performance optimization at a later date.

The TransformImage method is used to perform an imaging operation on the pixel data, such as convert to greyscale. The method specifies a Func parameter that’s used to perform a per-pixel operation. The Func is passed from the Xamarin.Forms PCL project into the method, and operates on each pixel component. At the moment the TransformImage method is hard-coded to place the result of the Func into each pixel component. This is purely for my own test purposes, for implementing a ConvertToGreyscale Func. It can easily be modified to not duplicate the result of the Func across all four colour components.

The ToImage method is then used to place the transformed pixel data back into the Android.Graphics.Bitmap. Note that the ToImage method creates a 32 bit image. An overload could be provided to create a 8 bit image.

A Dispose method is also provided to clean up the Android.Graphics.Bitmap instance and byte array of pixels.

The Bitmap class can then be invoked as follows:

1 public Task<Stream> TransformPhotoAsync (Func<byte, byte, byte, double> pixelOperation) 2 { 3 return Task.Run (() => { 4 var bitmap = new Bitmap (photoPath); 5 bitmap.ToPixelArray (); 6 bitmap.TransformImage (pixelOperation); 7 var androidBitmap = bitmap.ToImage (); 8 9 var memoryStream = new MemoryStream (); 10 androidBitmap.Compress (Android.Graphics.Bitmap.CompressFormat.Jpeg, 80, memoryStream); 11 memoryStream.Seek (0L, SeekOrigin.Begin); 12 bitmap.Dispose (); 13 14 return (Stream)memoryStream; 15 }); 16 }

A new Bitmap instance is created, with the path to the photo being passed into the constructor. The photo is read and converted to an array of pixels, transformed by the pixelOperation Func, and then converted into a new Android.Graphics.Bitmap before being returned for display by a Xamarin.Forms Image control. All of this work is wrapped in a Task.Run in order for it to be executed on a background thread.

Summary

This blog post has described how to access and manipulate pixel data in a Xamarin.Forms Android project, by implementing the Bitmap class. The Bitmap class implements the IBitmap interface that’s provided by the Xamarin.Forms PCL project. My next blog post will explain the implementation of the IBitmap interface in WinRT.

Wednesday, 2 December 2015

Accessing Image Pixel Data in a Xamarin.Forms App – iOS

Previously, I’ve described a basic architecture for accessing and manipulating pixel data from a Xamarin.Forms project. A Xamarin.Forms PCL project defines the IBitmap interface, which specifies the operations that must be implemented in each platform-specific project to access and manipulate pixel data.

In this blog post I’ll explain the operation of the Bitmap class in the Xamarin.Forms iOS project, which implements the IBitmap interface. The DependencyService can be used to invoke a method from the Xamarin.Forms PCL project, which in turn invokes IBitmap operations.

Disclaimer: The code featured here is alpha code, so all the usual caveats apply.

Implementation

The following code shows the Bitmap class implementation on iOS:

1 public class Bitmap : IBitmap<UIImage>
2 {
3 const byte bitsPerComponent = 8;
4 const byte bytesPerPixel = 4;
5 UIImage image;
6 readonly int width;
7 readonly int height;
8 IntPtr rawData;
9 byte[] pixelData;
10 UIImageOrientation orientation;
11
12 public Bitmap (UIImage uiImage)
13 {
14 image = uiImage;
15 orientation = image.Orientation;
16 width = (int)image.CGImage.Width;
17 height = (int)image.CGImage.Height;
18 }
19
20 public void ToPixelArray ()
21 {
22 using (var colourSpace = CGColorSpace.CreateDeviceRGB ()) {
23 rawData = Marshal.AllocHGlobal (width * height * 4);
24 using (var context = new CGBitmapContext (rawData, width, height, bitsPerComponent, bytesPerPixel * width, colourSpace, CGImageAlphaInfo.PremultipliedLast)) {
25 context.DrawImage (new CGRect (0, 0, width, height), image.CGImage);
26 pixelData = new byte[width * height * bytesPerPixel];
27 Marshal.Copy (rawData, pixelData, 0, pixelData.Length);
28 Marshal.FreeHGlobal (rawData);
29 }
30 }
31 }
32
33 public void TransformImage (Func<byte, byte, byte, double> pixelOperation)
34 {
35 byte r, g, b;
36
37 // Pixel data order is RGBA
38 try {
39 for (int i = 0; i < pixelData.Length; i += bytesPerPixel) {
40 r = pixelData [i];
41 g = pixelData [i + 1];
42 b = pixelData [i + 2];
43
44 // Leave alpha value intact
45 pixelData [i] = pixelData [i + 1] = pixelData [i + 2] = (byte)pixelOperation (r, g, b);
46 }
47 } catch (Exception ex) {
48 Console.WriteLine (ex.Message);
49 }
50 }
51
52 public UIImage ToImage ()
53 {
54 using (var dataProvider = new CGDataProvider (pixelData, 0, pixelData.Length)) {
55 using (var colourSpace = CGColorSpace.CreateDeviceRGB ()) {
56 using (var cgImage = new CGImage (width, height, bitsPerComponent, bitsPerComponent * bytesPerPixel, bytesPerPixel * width, colourSpace, CGBitmapFlags.ByteOrderDefault, dataProvider, null, false, CGColorRenderingIntent.Default)) {
57 image.Dispose ();
58 image = null;
59 pixelData = null;
60 return UIImage.FromImage (cgImage, 0, orientation);
61 }
62 }
63 }
64 }
65 }

The ToPixelArray method is used to convert the UIImage to a byte array of raw pixel data. The image’s pixel data is placed into unmanaged memory through the DrawImage method, and is referenced through the rawData IntPtr. It’s formatted as 32 bits per pixel, with each pixel being composed of a Red, Green, Blue, and Alpha channel. It’s then copied to the managed pixelData array, before the unmanaged memory is freed. Therefore, the pixelData array stores each pixel over four array elements (R, G, B, A).

The TransformImage method is used to perform an imaging operation on the pixel data, such as convert to greyscale. The method specifies a Func parameter that’s used to perform a per-pixel operation. The Func is passed from the Xamarin.Forms PCL project into the method, and operates on each pixel component. At the moment the TransformImage method is hard-coded to place the result of the Func into each pixel component. This is purely for my own test purposes, for implementing a ConvertToGreyscale Func (see previous blog post). It can easily be modified to not duplicate the result of the Func across all four colour components.

The ToImage method is then used to place the transformed pixel data in a new UIImage, before performing some cleanup to allow managed memory to be reclaimed. Note that the ToImage method creates a 32 bit image. An overload could be provided to create a 8 bit image.

The Bitmap class can then be invoked as follows:

1 public Task<Stream> TransformPhotoAsync (Func<byte, byte, byte, double> pixelOperation)
2 {
3 return Task.Run (() => {
4 var bitmap = new Bitmap (image);
5 bitmap.ToPixelArray ();
6 bitmap.TransformImage (pixelOperation);
7 return bitmap.ToImage ().AsJPEG ().AsStream ();
8 });
9 }

A new Bitmap instance is created, with a UIImage instance being passed into the constructor. The UIImage is converted to an array of pixels, transformed by the pixelOperation Func, and then converted into a new UIImage before being returned for display by a Xamarin.Forms Image control. All of this work is wrapped in a Task.Run in order for it to be executed on a background thread.

Summary

This blog post has described how to access and manipulate pixel data in a Xamarin.Forms iOS project, by implementing the Bitmap class. The Bitmap class implements the IBitmap interface that’s provided by the Xamarin.Forms PCL project. My next blog post will explain the implementation of the IBitmap interface on Android.

Monday, 30 November 2015

Accessing Image Pixel Data in a Xamarin.Forms App

As a Xamarin employee, I spend a lot of my time writing code and content that ultimately ends up on the Xamarin Developer Center. Because of this, it’s not often that I have things to say on this blog, as I’ve already said them in official Xamarin code/content. However, I’m working on a longer term project that won’t be published for a while, and it offers me the opportunity to share some early code, that’s often been requested by the community. Specifically, I’ve been working on accessing image pixel data from a Xamarin.Forms app, so that users will be able to perform image manipulation from Xamarin.Forms.

The purpose of this blog post is to describe a basic architecture for accessing and manipulating pixel data from a Xamarin.Forms project. This will involve using the DependencyService to execute platform-specific code to access and manipulate pixel data. However, the imaging operations can be defined in the Xamarin.Forms PCL project.

Disclaimer: This code featured here is alpha code, so all the usual caveats apply.

Implementation

In my Xamarin.Forms PCL project I’ve created the IBitmap interface, which defines the operations that must be implemented in each platform-specific project.

1 public interface IBitmap<T>
2 {
3 void ToPixelArray ();
4
5 void TransformImage (Func<byte, byte, byte, double> pixelOperation);
6
7 T ToImage ();
8 }

The ToPixelArray method is used to convert the native image type to a byte array of raw pixel data. The TransformImage method is used to perform an imaging operation on the pixel data, such as convert to greyscale, convert to sepia, colour balance etc. The ToImage method is then used to convert the transformed pixel data back to the native image type. Eventually I expect there to be more operations specified in the IBitmap interface, including overloads of some of the existing operations.

The TransformImage method specifies a Func parameter. This Func will be used to perform per-pixel operations. For example, the ConvertToGreyscale Func, shown below, is used to convert an image to its greyscale representation:

1 public static class ImagingOperations
2 {
3 public static Func<byte, byte, byte, double> ConvertToGreyscale = (r, g, b) => 0.299 * (r - g) + g + 0.114 * (b - g);
4 }

This Func will be passed from the Xamarin.Forms PCL project into the TransformImage implementation in each platform specific project, where it will be executed on each pixel in the image. The advantage of this approach is that any per-pixel imaging operations can all be defined once, in the Xamarin.Forms PCL project.

Summary

This blog post has described a basic architecture for accessing and manipulating pixel data from a Xamarin.Forms project. My next blog post will explain the implementation of the IBitmap interface in iOS.

Wednesday, 12 August 2015

Prism for the Windows Runtime Templates for Visual Studio 2015

I was recently asked if I had any plans to update the Prism WinRT templates to support VS2015. To be honest I was surprised that anyone is still using Prism WinRT, so had no plans to update the templates to VS2015. But in order to support people who’ve stuck with it, I decided to do an update. My intention was to add support for VS2015 to the existing template VSIX. However, this turned out not to be possible for two reasons:

  • Creating a Prism WinRT project relies on the Microsoft.VisualStudio.WinRT.TemplateWizards assembly. VS2012/2013 used v12 of this assembly, with VS2015 using v14. This presents a problem as a machine that only has VS2015 will only have the v14 assembly.
  • The location where the Prism WinRT project and item templates should reside has changed in VS2015.

The simplest solution was to build a new VSIX for VS2015.

I tried to upload the VSIX to the Visual Studio Gallery and it fails to upload, despite working when installing locally. This is because some of the paths in the VSIX would be too long if it’s installed on an Windows XP machine. While I can shorten the path a little, it’s not enough to pass Visual Studio Gallery validation. There are other solutions available but it’s not worth investing the time to solve the issue for these templates, when there’ll be a brand new set for Prism 6.

So in the meantime, if you want Prism WinRT templates for VS2015 you can download them from here.

Sunday, 5 July 2015

Revisiting Prism for Xamarin.Forms

Previously I wrote about how to create a flexible and maintainable Xamarin.Forms app with Prism. In the last month Prism for Xamarin.Forms has undergone some more work by Brian Lagunas, and a couple of new features have been implemented. This blog post will investigate the new features provided by the latest release of Prism for Xamarin.Forms.

Navigation

There are two improvements made to navigation in the latest release of Prism for Xamarin.Forms. The first concerns how you register types for navigation, and how to perform navigation to registered types. An overload to IUnityContainer.RegisterTypeForNavigation has been added that accepts two generic types. The first argument is the View type, with the second argument being a Class type (most likely a ViewModel type).

1 protected override void RegisterTypes()
2 {
3 Container.RegisterTypeForNavigation<PhotoPage, PhotoPageViewModel>();
4 }

A corresponding change has been made to INavigationService.Navigate method to accept a generic in place of a string to identify the View to navigate to.

1 public void Navigate()
2 {
3 ...
4 this.NavigationService.Navigate<PhotoPageViewModel>(parameters);
5 }


The advantage of this approach is that it allows you specify a ViewModel for navigation, eliminating the magic string that was previously used.

The second improvement relates to how the correct INavigationService instance is obtained in a ViewModel for navigation. The previous approach involved having your ViewModel implement the INavigationServiceAware interface. in order to add a NavigationService instance to your ViewModel. In the latest release of Prism for Xamarin.Forms the INavigationService can be directly injected into the ViewModel constructor.

1 public MainPageViewModel(INavigationService navigationService)
2 {
3 this.NavigationService = navigationService;
4 ...
5 }

Please note that in order for Prism to inject the proper INavigationService instance via the constructor, you must name the parameter navigationService. This is because each page in Xamarin.Forms has its own navigation instance. So Prism can’t just register a global navigation service for all pages. It has to have a navigation service specific to each page and ViewModel. Prism uses the Unity dependency injection container to resolve the service through constructor injection, and because Unity doesn’t allow you to look for a type Prism instead looks for a specific name, in this case navigationService.

DependenyService improvements

Xamarin.Forms provides the DependencyService class to enable shared code to easily resolve interfaces to platform-specific implementations. However, it is not always easy to test ViewModels that make a call to the DependencyService class. A typical implementation without Prism is shown below.

1 public MainPageViewModel()
2 {
3 _textToSpeech = DependencyService.Get<ITextToSpeech>();
4 SpeakCommand = new DelegateCommand(Speak);
5 }
6
7 private void Speak()
8 {
9 _textToSpeech.Speak(TextToSay);
10 }

Prism improves this experience by enabling you to ask for your dependency as an argument in your ViewModel constructor.

1 public MainPageViewModel(ITextToSpeech textToSpeech)
2 {
3 _textToSpeech = textToSpeech;
4 SpeakCommand = new DelegateCommand(Speak);
5 }
6
7 private void Speak()
8 {
9 _textToSpeech.Speak(TextToSay);
10 }

The advantage of this approach is that it eliminates the call to the DependencyService class, helping to make your ViewModel class more easily testable. For an example that demonstrates using Prism with the TextToSpeech see this sample app.

Summary

Prism for Xamarin.Forms provides loosely-coupled components that help you to produce Xamarin.Forms apps that are flexible, maintainable, and testable. The latest additions to Prism enhance the navigation experience and make it easier to test ViewModels that use the Xamarin.Forms DependencyService class.

The sample app can be downloaded here.

Wednesday, 13 May 2015

Creating a flexible and maintainable Xamarin.Forms app with Prism

Prism, a set of libraries developed by Microsoft, helps you to design and build apps using loosely-coupled components that can evolve independently but that can be easily integrated into the overall app. Prism now includes support for Xamarin.Forms in the form of a preview library. This library helps to produce Xamarin.Forms apps that are flexible, maintainable, and testable.

Prism is designed to help developers create apps that need to accomplish the following:

  • Address common app development scenarios.
  • Separate the concerns of presentation, presentation logic, and model through support for the Model-View-ViewModel (MVVM) pattern.
  • Use an architectural infrastructure to produce a consistent and high quality app.

The logical architecture of a typical Xamarin.Forms app that uses Prism is shown in the following diagram. Grey items are provided by Prism, with blues items having to be created by the developer.

image

In this blog post I’ll take the sample app developed in my previous blog post, and convert it to use Prism in order to further the separation of concerns in the sample app. I’ll assume that you are familiar with the Unity dependency injection container. However, you are not required to use Unity, or any other dependency injection container, in order to use Prism.

Implementation

Bootstrapping the app

The App class, in the XamarinPhotoViewer project, has the responsibility for bootstrapping the app.

1 public class App : Application
2 {
3 public App()
4 {
5 var bootstrapper = new Bootstrapper();
6 bootstrapper.Run(this);
7 }
8 }

This is achieved by using the App constructor to create an instance of the Bootstrapper class, and run it. The Bootstrapper class is simply a class that initializes the services that Prism will be using.

1 public class Bootstrapper : UnityBootstrapper
2 {
3 protected override Page CreateMainPage()
4 {
5 return Container.Resolve<MainPage>();
6 }
7
8 protected override void RegisterTypes()
9 {
10 Container.RegisterTypeForNavigation<PhotoPage>();
11 }
12 }

The Bootstrapper class derives from the UnityBootstrapper class, which is a Prism provided class that handles the initialization of the Unity container. The Bootstrapper class overrides the CreateMainPage method in order to return the page to be used as the root page of the app, and overrides the RegisterTypes method in order to register the PhotoPage view so that it can be used in navigation.

Connecting view models to views

Prism provides a view model locator object that is responsible for the instantiation of view models and their association to views. This has the advantage that the app has a single class that is responsible for the instantiation of view models.

The ViewModelLocator class has an attached property, AutowireViewModel that is used to associate view models with views. In the view’s XAML, this attached property is set to true to indicate that the view model should be automatically connected to the view.

1 <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
2 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
3 xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
4 prism:ViewModelLocator.AutowireViewModel="true"
5 x:Class="XamarinPhotoViewer.Views.MainPage">
6 ...
7 </ContentPage>

The ViewModelLocator object uses a convention-based approach to locate and instantiate view models from views. This convention assumes that view models are in the same assembly as the view types, that view models are in a .ViewModels child namespace, that views are in a .Views child namespace, and that view model names correspond with view names and end with “ViewModel”.

Updating a view in response to changes in the view model

All view model classes that are accessible to the view should implement the INotifyPropertyChanged interface. This allows view models to provide change notifications to any data-bound controls in the view when the underlying property value changes. However, this can be repetitive and error prone. Therefore, Prism provides the BindableBase class that implements the INotifyPropertyChanged interface.

Each view model class in the sample app derives from the BindableBase class. Therefore, each view model class uses the SetProperty method in the BindableBase class to provide property change notification.

1 public class PhotoPageViewModel : BindableBase, INavigationAware
2 {
3 ...
4 private string _image;
5 public string Image
6 {
7 get { return this._image; }
8 set { SetProperty(ref this._image, value); }
9 }
10 ...
11 }

The call to the SetProperty method simply updates the value of the property if it has changed, and provides property change notification to the view.

For more information about data binding in Xamarin.Forms, see Data Binding Basics.

Triggering actions in the view model from the view

Apps typically invoke an action in response to a user action, such as a button click, that can be implemented by creating an event handler in the view’s code-behind file. However, in the MVVM pattern, the responsibility for implementing the action lies with the view model, and you should try to avoid placing code in the view’s code-behind file.

Commands provide a convenient approach to represent actions that can be bound to controls in the view. View models typically expose command properties, for binding from the view, that are object instances that implement the ICommand interface. XAML inherently supports commands and many controls provide a Command property that can be data bound to an ICommand object in the view model. For more information about Xamarin.Forms support for ICommand, see From Data Bindings to MVVM.

Prism provides the DelegateCommand class to implement commands in view models.

1 public DelegateCommand NavigateCommand { get; private set; }
2
3 ...
4
5 public PhotoPageViewModel(INavigationService navigationService)
6 {
7 ...
8 this.NavigateCommand = new DelegateCommand(GoBack);
9 }
10
11 private void GoBack()
12 {
13 this.NavigationService.GoBack();
14 }

The NavigateCommand is exposed to the view through a read-only property that’s initialized in the view model constructor.

1 <Button Command="{Binding NavigateCommand}"
2 Text="Go back" />

When the command is invoked from the view, it simply forwards the call to the GoBack method in the view model class via the delegate specified in the view model constructor.

Navigating between pages

The XamarinPhotoViewer sample app triggers navigation requests from user interaction in the views. These requests are to navigate between the MainPage and PhotoPage views.

Prism’s INavigationAware interface allows an implementing view model class to participate in a navigation operation. This interface defines the OnNavigatedFrom and OnNavigatedTo methods that are called during a navigation operation. The OnNavigatedFrom method allows the page being navigated away from to perform any cleanup before it is disposed of. In the view model class for the page being navigated to, its OnNavigatedTo method is called after navigation is complete. The OnNavigatedTo method allows the newly displayed page to initialize itself by using any navigation parameters passed to it. For example, the OnNavigatedTo method in the PhotoPageViewModel class accepts a Photo parameter that is used to display data on the view.

Prism provides the PageNavigationService class that allows view models to perform navigation operations without taking a dependency on UI types. When view model classes are instantiated, Unity will inject the dependencies that are required including the PageNavigationService instance. View models can then invoke the Navigate method on the PageNavigationService instance to cause the app to navigate to a particular view in the app, or the GoBack method to return to the previous view.

1 public void Navigate()
2 {
3 var parameters = new NavigationParameters();
4 parameters.Add("photo", this.Photo);
5 this.NavigationService.Navigate("PhotoPage", parameters);
6 }

The Navigate method accepts a string parameter that represents the page to be navigated to, and a navigation parameter that represents the data to pass to the page being navigated to. Any data being passed to the page being navigated to will be received by the OnNavigatedTo method of the view model class for the page type.

Placing the navigation logic in view model classes enables navigation logic to be exercised through automated tests. In addition, view models can then implement logic to control navigation to ensure that any required business rules are enforced.

Summary

Prism for Xamarin.Forms provides loosely-coupled components that help you to produce Xamarin.Forms apps that are flexible, maintainable, and testable. In particular, Prism’s support for MVVM enables you to easily provide a clean separation of concerns between the appearance and layout of the UI from the responsibility for the business logic. This helps to ensure that an app will be easier to test, maintain, and evolve.

The sample app can be downloaded here.