Xamarin.Forms: Dependency Injection

To recap, I’m writing a shopping cart app for Windows Phone, Android, and iOS.  The purpose of the app is primarily to let me use Forms.  Each post will build on top of the previous one.

Last time I added a product search that uses a barcode scanner using the ZXing component.  Today I plan on cleaning up app startup by incorporating a dependency injection framework.

Recap and Code

This is the sixth post in the series, you can find the rest here:

  • Day 0:  Getting Started (blog / code)
  • Day 1:  Binding and Navigation (blog / code)
  • Day 2:  Frames, Event Handlers, and Binding Bugs (blog / code)
  • Day 3:  Images in Lists (blog / code)
  • Day 4:  Search and Barcode Scanner (blog / code)
  • Day 5:  Dependency Injection (blog / code)

The latest version of the code can always be accessed on the GitHub project page.

Cleanup

Before starting up, I’d like to perform a little bit of clean up.  There is a bug in the XF template.  When the reference for the platform project (e.g., ShoppingCart.WinPhone) to the core project (i.e., ShoppingCart) is created the project id is missing.

This causes a few subtle problems, the most annoying of which is that renames in the core project are not propagated to the dependent projects.  For instance, if I rename the FirstPage property of the App class, the reference in ShoppingCart.WinPhone.MainPage will not be updated.

image

This can easily be solved by

  1. Removing the reference to ShoppingCart from each of the platform projects
  2. Adding the reference back

As a reminder, to remove the reference, just expand the References node under ShoppingCart.WinPhone in Solution Explorer, select the reference, and hit the delete key.

image

To add the reference back, right click on the References node, select Add Reference, and tick the checkbox next to ShoppingCart in the Projects tab.

image

Doing a quick diff of your CSPROJ after this you can see that the Project element has been added to the reference.

<!-- Before -->
<ProjectReference Include="..\ShoppingCart\ShoppingCart.csproj">
    <Name>ShoppingCart</Name>
</ProjectReference>

<!-- After -->
<ProjectReference Include="..\ShoppingCart\ShoppingCart.csproj">
    <Project>{8eb80e50-ef54-451b-9768-3d38e2a3e122}</Project>
    <Name>ShoppingCart</Name>
</ProjectReference>

Dependency Service vs. Injection

Last week I used XF’s DependencyService class to resolve application specific dependencies.  This worked by registering the dependency in the Android and WinPhone projects by adding a Dependency attribute like this:

[assembly: Xamarin.Forms.Dependency(typeof(DroidScanner))]

and then resolving it in the core project with a call to DependencyService.Get

var scanner = DependencyService.Get<IScanner>();

While this worked for what I needed last week, it does have the requirement that resolved type (i.e., DroidScanner in my example) has a default constructor.  This means that unlike a dependency injection framework, you cannot rely on the framework to create all of your dependencies in one go.  You have to manually resolve and compose them yourself.

Dependency Injection on PCL

There are many .Net DI frameworks out there.  My go to DI framework is Ninject but as of now it doesn’t support PCL.  So, after a little digging for PCL frameworks.  The key features that I look for are

  • Constructor injection
  • Registration with generics

I decided to give AutoFac a try.  I’ve never used it before, but by looking at the documentation it looked like it meets my requirements.

Starting Up AutoFac

The first thing I need to do is to get AutoFac.  In my main project (ShoppingCart) I right click to add a nuget package, search for AutoFac, and cross my fingers that it installs with out complaint.  Somewhat to my surprise, NuGet downloaded and added it to my project with out complaint.  I know it claimed to be PCL friendly, but I’m always surprised when installing something just works the first time.

Before I remove the usage of DependencyService, I need to configure the rest of the services and view models to be created by the DI framework.  I’ll do this in a dedicated class called ContainerCreator.  This is a habit I got from Ninject where you can create module classes to do all your bindings.  It keeps everything in one place and I like it in Ninject so I’ll see how well it works in AutoFac land.

public class ContainerCreator
{
  public static IContainer CreateContainer()
  {
    ContainerBuilder cb = new ContainerBuilder();

    // Services
    cb.RegisterType<LoginService>().As<ILoginService>().SingleInstance();
    cb.RegisterType<ProductLoader>().As<IProductLoader>().SingleInstance();
    cb.RegisterType<ProductService>().As<IProductService>().SingleInstance();
    cb.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();
    cb.RegisterInstance(DependencyService.Get<IScanner>()).As<IScanner>().SingleInstance();

    // View Models
    cb.RegisterType<CategoriesListViewModel>().SingleInstance();
    cb.RegisterType<LoginViewModel>().SingleInstance();
    cb.RegisterType<ProductsListViewModel>().SingleInstance();
    cb.RegisterType<ProductViewModel>().SingleInstance();
    cb.RegisterType<WelcomeViewModel>().SingleInstance();

    return cb.Build();
  }
}

I’m setting up all of my registrations for my services which implement interfaces and my view models which are registered to themselves.  I’m also registering everything as singletons which will probably change later, but this should get me going.  Again, I’m still using the DependencyService to get my IScanner, this is just an intermediary step for now.  The goal is to remove that by the end of this post.

Next, I’ll clean up App to make use of the AutoFac container

private static readonly IContainer _container;

static App()
{
    _container = ContainerCreator.CreateContainer();

    NaviService = _container.Resolve<INavigationService>() as NavigationService;

    // Pages
    WelcomePage = new WelcomePage();
    LoginPage = new LoginPage();
    CategoriesListPage = new CategoriesListPage();
}

The view model properties now just resolve their values directly from the container when called.  They are all pretty much the same, here’s one as an example.

public static CategoriesListViewModel CategoriesListViewModel
{
    get
    {
        return _container.Resolve<CategoriesListViewModel>();
    }
}

Starting the app up, it should work exactly like it did before.  And it does.  Success.

Removing DependencyService

Now we can get to work on removing the DependencyService.  Technically though there is no reason just yet to remove it.  It works just fine for my app because DroidScanner and WinPhoneScanner both have parameterless constructors.  So I’m going to break it now by adding some parameters.  The most common parameter in most of my apps is a logger, so I’ll add one here.

I’ll add ILogger, an interface for my logger:

public interface ILogger
{
    void Info(string message);
    void Info(string format, params object[] args);
    void Info(Exception ex, string message);
    void Info(Exception ex, string format, params object[] args);

    void Error(string message);
    void Error(string format, params object[] args);
    void Error(Exception ex, string message);
    void Error(Exception ex, string format, params object[] args);
}

And then a Droid and WinPhone specific implementations each using their platform specific methods for logging:  Log and Debug.WriteLine respectively.   They are kind of long and boring, so here’s just a simple example from both:

public class DroidLogger : ILogger
{
    private const string APP_NAME = "ShoppingCart";

    public void Info(string message)
    {
        Log.Info(APP_NAME, message);
    }
}
public class WinPhoneLogger : ILogger
{
    public void Info(string message)
    {
        Console.WriteLine("INFO:  " + message);
    }
}

Next we add logging to each of the IScanner implementations.  Here’s the WinPhone implementation, the Droid version is identical

private readonly ILogger _logger;

public WinPhoneScanner(ILogger logger)
{
    _logger = logger;
}

public async Task<ScanResult> Scan()
{
    _logger.Info("Starting the barcode scanner.  Stand back.");

    var scanner = new MobileBarcodeScanner(MainPage.DispatcherSingleton);
    // ...
}

Hooray, the call to DependencyService.Get now fails with this error:  System.MissingMethodException:  No parameterless constructor defined for this object.  Time to fix it.

First I’m going to change the name of the ContainerCreator to AppSetup and make it a non-static class.  My plan is to enable custom app setup by overriding methods in this object.  Here’s what it looks like now:

public class AppSetup
{
    public IContainer CreateContainer()
    {
        ContainerBuilder cb = new ContainerBuilder();
        RegisterDepenencies(cb);
        return cb.Build();
    }

    protected virtual void RegisterDepenencies(ContainerBuilder cb)
    {
        // Services
        cb.RegisterType<LoginService>().As<ILoginService>().SingleInstance();
        cb.RegisterType<ProductLoader>().As<IProductLoader>().SingleInstance();
        cb.RegisterType<ProductService>().As<IProductService>().SingleInstance();
        cb.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();

        // View Models
        cb.RegisterType<CategoriesListViewModel>().SingleInstance();
        cb.RegisterType<LoginViewModel>().SingleInstance();
        cb.RegisterType<ProductsListViewModel>().SingleInstance();
        cb.RegisterType<ProductViewModel>().SingleInstance();
        cb.RegisterType<WelcomeViewModel>().SingleInstance();
    }
}

The registrations have been moved to a dedicated method RegisterDependencies which takes the ContinerBuilder to use to add your registrations.  I’ve removed the instance registration that was was using the XF DependencyService (that was the goal the whole time).  If you notice, the method is virtual.  The idea is to override this for each platform that needs to. Here’s the WinPhone override (the Droid version is very similar):

public class WinPhoneSetup : AppSetup
{
    protected override void RegisterDepenencies(ContainerBuilder cb)
    {
        base.RegisterDepenencies(cb);

        cb.RegisterType<WinPhoneLogger>().As<ILogger>().SingleInstance();
        cb.RegisterType<WinPhoneScanner>().As<IScanner>().SingleInstance();
    }
}

All that I’m doing here is registering the WinPhone logger and scanner.  The two bits of platform specific implementations that I have.  Notice that I call into my base implementation to handle all of the rest of the registrations.

There’s a small problem though.  The WinPhoneSetup class won’t compile.  It doesn’t know anything about AutoFac.  Right now only my core project references AutoFac.  I could just add a reference for the WinPhone project, but I know that all of the other projects will need one as well, so I’ll add a reference for each of the projects in one go.  The easiest way to do this is to right click on the Solution (not the projects) and select Manage NuGet Packages for Solution.  From there you can select the Installed Packages tab and click the “Manage” button for AutoFac.  Then just tick all of the check boxes and click OK.

image Next in order to have App be able to use different versions of AppSetup I change the static constructor to a static method called Initialize that takes the AppSetup object to use.

public static void Init(AppSetup appSetup)
{
    _container = appSetup.CreateContainer();

    NaviService = _container.Resolve<INavigationService>() as NavigationService;

    WelcomePage = new WelcomePage();
    LoginPage = new LoginPage();
    CategoriesListPage = new CategoriesListPage();

    // Startup Page
    StartupPage = WelcomePage;// CategoriesListPage;
}

Now all I need to do is to call Init from the Droid and WinPhone projects.  In MainActivity.OnCreate we add the call Init with the DroidSetup object

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    Xamarin.Forms.Forms.Init(this, bundle);
    App.Init(new DroidSetup());
    SetPage(App.StartupPage);
}

And in the constructor for MainPage.xaml.cs we call Init with an instance of WinPhoneSetup.

public MainPage()
{
    InitializeComponent();
    Forms.Init();

    App.Init(new WinPhoneSetup());
    Content = ShoppingCart.App.StartupPage.ConvertPageToUIElement(this);
}

With AutoFac in place I can delete the two ServiceRegistration classes I had that registered my classes with the DependencyService.  And now all I have to do is to spin up the app and see that the log messages in the console.

Happy Coding

Xamarin.Forms: Search and Barcode Scanner

To recap, I’m writing a shopping cart app for Windows Phone, Android, and iOS.  The purpose of the app is primarily to let me use Forms.  Each post will build on top of the previous one.

Last time I worked I added asynchronously loaded images to a list view.  Today I plan on adding a product search that uses a barcode scanner using the ZXing component.

Recap and Code

This is the fifth post in the series, you can find the rest here:

  1. Day 0:  Getting Started (blog / code)
  2. Day 1:  Binding and Navigation (blog / code)
  3. Day 2:  Frames, Event Handlers, and Binding Bugs (blog / code)
  4. Day 3:  Images in Lists (blog / code)
  5. Day 4:  Search and Barcode Scanner (blog / code)

The latest version of the code can always be accessed on the GitHub project page.

Search

Before I implement search with a barcode, it’ll be easier if I add a search box.  For now, I’ll just add it on the categories page.  This should be simple, I’ll throw up a text box and a button.

<StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal">
  <Entry Text="{Binding SearchTerm}"
         Placeholder="Search"
         HorizontalOptions="FillAndExpand" />
  <Button Text ="Search"
    Command="{Binding SearchCommand}" />
</StackLayout>

Next I wire them into the view model.

private readonly RelayCommand _searchCommand;

public CategoriesListViewModel(IProductService service, INavigationService navi)
{
    _searchCommand = new RelayCommand(async () =>
    {
        var items = (await _service.Search(SearchTerm))
                    .OrderByDescending(i => i.Rating)
                    .ToList();

        if (items != null && items.Any())
        {
            Page page = items.Count == 1
                 ? page = App.GetProductPage(items.First())
                 : page = App.GetProductsListPage(items, SearchTerm);

            await _navi.PushAsync(page);
            SearchTerm = string.Empty;
        }
        else
        {
            await _navi.DisplayAlert("Error", "No results for search " + SearchTerm);
        }
    },
    () => !string.IsNullOrWhiteSpace(SearchTerm));
}

public ICommand SearchCommand { get { return _searchCommand; } }

public string SearchTerm
{
    get { return GetValue<string>(); }
    set
    {
        SetValue(value);
        _searchCommand.RaiseCanExecuteChanged();
    }
}

If our search has exactly one result, then we go directly to that product page; if there are multiple results, we show them in a list.

The ProductService already has a stub for search, but was only half implemented.

public async Task<List<Product>> Search(string searchString)
{
    var items = await _itemsAsync;

    if (string.IsNullOrWhiteSpace(searchString)) return items;

    searchString = searchString.ToLower();
    var filterd = items.Where(i => i.Name.ToLower().Contains(searchString))
                       .ToList();

    return filterd;
}

Adding a Component

The first step in using a component is to add it to your project.  Right click on the “Components” folder in your Droid or iOS project and select “Ge More Components…”

image

I searched for a barcode scanner and got a list of packages.  ZXing sounds familiar and supports all platforms so I go with that.

image

Window’s phone is a little simpler in that I can just download the package from NuGet:

Install-Package ZXing.Net.Mobile

Using a Component

Since each platform references its own implementation of the barcode scanner software, I now need to create a device agnostic interface in the common project.

public interface IScanner
{
    Task<ScanResult> Scan();
}

public class ScanResult
{
    public string Text { get; set; }
}

I then implement these interfaces for each of the platforms.

Android first:

public class DroidScanner : IScanner
{
    public async Task<ScanResult> Scan()
    {
        var scanner = new MobileBarcodeScanner(Forms.Context)
        {
            UseCustomOverlay = false,
            BottomText = "Scanning will happen automatically",
            TopText = "Hold your camera about \n6 inches away from the barcode",
        };

        var result = await scanner.Scan();

        return new ScanResult
        {
            Text = result.Text,
        };
    }
}

The MobileBarcodeScanner takes the current instance of the Android context.  Because this is a common requirement in Android API’s Xamarin exposes the current context in the static property Forms.Context.

WindowsPhone is essentially the same, just a different constructor:

public class WinPhoneScanner : IScanner
{
    public async Task<ScanResult> Scan()
    {
        var scanner = new MobileBarcodeScanner(MainPage.DispatcherSingleton)
        {
            UseCustomOverlay = false,
            BottomText = "Scanning will happen automatically",
            TopText = "Hold your camera about \n6 inches away from the barcode",
        };

        var result = await scanner.Scan();

        return new ScanResult
        {
            Text = result.Text,
        };
    }
}

Next I register the device specific implementations with the XF DependencyService.  In my Droid project I create a file called ServiceRegistration and add the following lines

using ShoppingCart.Droid.Services;

[assembly: Xamarin.Forms.Dependency(typeof(DroidScanner))]

A similar file is created for WP:

using ShoppingCart.WinPhone.Services;

[assembly: Xamarin.Forms.Dependency(typeof(WinPhoneScanner))]

Now to create an instance of IScanner I resolve it from the DependencyService:

IScanner scanner = DependencyService.Get<IScanner>();

Now all I have to do is wire up a new button to to launch the scanner and use the results.

ScanCommand = new RelayCommand(async () =>
{
    var result = await _scanner.Scan();

    SearchTerm = result.Text;
    Search();
});

The scan command just calls into the search implementation I wrote above.

Adding Permissions

And finally, I just need to add in the permission to access the camera, otherwise the barcode scanner component won’t be able to start up at all.  On Windows phone open up the WMAppManifest, switch to the Capabilities tab, and make sure that ID_CAP_ISV_CAMERA is checked.

imageOr just edit the file by hand and add the permission by hand.

<Capability Name="ID_CAP_ISV_CAMERA" />

Android is similar. Right click the project, select Properties, go to the Android Manifest tab, and select CAMERA in the Required permissions section.

image

Again, you can do this manually by editing the AndroidManifest.xml file directly and adding the CAMERA permission.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
  <uses-sdk />
  <application></application>
  <uses-permission android:name="android.permission.CAMERA" />
</manifest>

Happy coding

Xamarin.Forms: Images in Lists

To recap, I’m writing a shopping cart app for Windows Phone, Android, and iOS.  The purpose of the app is primarily to let me use Forms.  Each post will build on top of the previous one.

Last time I worked through some bugs in XF’s binding and cleaned up the layout a bit.  Today the plan is to add product photos to make the list of products and the product pages look prettier.

Recap and Code

This is the fourth post in the series, you can find the rest here:

  • Day 0:  Getting Started (blog / code)
  • Day 1:  Binding and Navigation (blog / code)
  • Day 2:  Frames, Event Handlers, and Binding Bugs (blog / code)
  • Day 3:  Images in Lists (blog / code)

The latest version of the code can always be accessed on the GitHub project page.

Bugs fixed

Last week I ran into a known bug where XF wasn’t properly responding to IPropertyChaged events.  At the time there was a fix in a beta build of Xamarin.Forms but I had trouble getting the beta dlls to run in my app.  Since then the fix has been officially released.  So, I updated all my nuget packages; lo and behold binding now works as expected.

Long story short:  Xamarin fixed the bug quickly and correctly.  Good for them.

Cleaning the Data

A little nitpicky, but while playing with my app I noticed that the product names don’t look like product names.  They are all lower cases and have odd punctuation.  I wanted to clean this up quickly so I grabbed Humanizer and added some post processing on the client after loading the products.

item.Name = item.Name
                .Titleize()
                .Replace(".", string.Empty);
item.Description = item.Description
                       .Humanize(LetterCasing.Sentence);

Now, if I want to show “product pictures” I’ll need to get those photos from somewhere.  From an unrelated undertaking I had a list of 300+ photos from Imgur.  Imgur also has a nice feature where you can request the image as an icon or full size.  My data lives in a single string of json which is deserialized at startup.  I want to be lazy and not update each item in that list manually so I’m taking a shortcut.  I added the Imgur ids to a queue and then in my post-process of the item, I add the icon and image urls.  Note the “s” at the end of the IconUrl.  That’s Imgur’s way to specify a “small square” icon.

private static void UpdateItem(Product item, string imgurId)
{
    item.ImageUrl = string.Format("http://i.imgur.com/{0}.jpg", imgurId);
    item.IconUrl = string.Format("http://i.imgur.com/{0}s.jpg", imgurId);
}

Now that I have all my data, I’ll start displaying the photos.

Inserting Images

I’m going to start with adding the image to the product page.  it’s just one image on the page so it should be pretty simple.

<ScrollView>
  <StackLayout VerticalOptions="FillAndExpand" Padding="50">

    <Label Text="{Binding Product.Name}"
      HorizontalOptions="Center"
      Font="Bold,Large" />

    <Image Aspect="AspectFill"
            HorizontalOptions="FillAndExpand"
            Source="{Binding Product.ImageUrl}" />

    <Label Text="{Binding Product.Description}"
      HorizontalOptions="Start"
      Font="Medium" />

    <Label Text="{Binding Product.Price, StringFormat='{0:c}'}"
      HorizontalOptions="Start"
      Font="Bold,Medium" />

  </StackLayout>
</ScrollView>

All I needed to do was add an Image element and bind the source to the product’s ImagUrl property.  The image will automatically be downloaded and cached for me.  According to the documentation the cache lasts one day by default but is configurable.  You can even turn the cache off.

This worked pretty well out of the box, everything loaded up very quickly.  The only caveat is that some of my pictures are fairly long so the description and text are pushed off the page.  Wrapping the entire StackLayout in a ScrollView allows me to scroll down and see the rest of my content.

screenshot

Moving to the list view, all I do was bind against the IconUrl in the Product model class. Remember, this is the smaller thumbnail provided to us by Imgur.

<ListView ItemsSource="{Binding Products}" ItemSelected="OnItemSelected">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="10">

          <Image Aspect="AspectFill"
                 HeightRequest ="75" WidthRequest="75"
                 Source="{Binding IconUrl}" />

          <Label Text="{Binding Product.Name}" YAlign="Center" Font="Large" />
        </StackLayout>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

I know I want the images to all be the same size so I set the width and height to be 75 pixels. The Aspect property will do its best to show as much of the image as possible, clipping it where needed.  As you can see, I also needed to add a horizontal StackLayout because the data template now has two items in it.  I’ve also upped the text size from before, it was hard to click an item in the list because it was too small.

Here’s the result:

screenshot

It doesn’t look too bad, but there is a problem:  it takes a long time to load.  Since XF synchronously loads the images, the app is completely blank and unresponsive for 2 to 5 seconds.

Researching the Slow

The app hanging when loading a product list is unacceptable.  So the first thing I did to counteract this was to take the network out of the equation.  I added a loading image as a resource to the app.  Since I wanted the same image on all platforms, I added it directly to the PCL project as an EmbeddedResource.

image

Just for testing, I modified my model to expose this image instead of the image from the web and bound my view to that instead.

public ImageSource IconSource
{
    get
    {
        string resource = "ShoppingCart.Resouces.placeholderImageSmall.png";
        return ImageSource.FromResource(resource);
    }
}
<Image Aspect="AspectFill"
       HeightRequest ="75" WidthRequest="75"
       Source="{Binding IconSource}" />

The resource path is separated by dots and includes the assembly name as well as any sub folders.  In my example above, the file “placeholderImageSmall.png” is in the “Resources” folder (which I created) in the “ShoppingCart” project.

With this change, the page loads instantly, but doesn’t look quite as nice since every product is using the same placeholder image.

screenshot

Since XF doesn’t do the load asynchronously, I need to figure out how to display the loading icon while the image is downloaded from the web in the background.

If I was in a pure WPF world, I’d use Priority Binding.  This lets you set a list of locations to get the binding value from, marking some as asynchronous.  Sadly, this is not supported in XF, so that’s right out.

So this means I need to roll it by hand.

Speeding Things Up

I already have a class that manages binding to the result of a task.  I used this last time for my product list which is (theoretically) coming from a slow source.  It is Stephen Cleary’s NotifyTaskCompletion.  This is a good start, but it returns null as the result until the task completes.  In my case I want it to return a default value (my place holder image).  I tweak the constructor and the result property just a touch to get the implementation I want.

private readonly TResult _defaultResult;

public NotifyTaskCompletion(Task<TResult> task, TResult defaultResult = default(TResult))
{
    _defaultResult = defaultResult;
    Task = task;

    if (!task.IsCompleted)
    {
        var _ = WatchTaskAsync(task);
    }
}

public TResult Result
{
    get
    {
        return (Task.Status == TaskStatus.RanToCompletion)
          ? Task.Result
          : _defaultResult;
    }
}

The constructor now takes the default value, with a default value of default(TResult) so we don’t break any existing uses of the class.

Next a few helpers to make using this for images simple:

public static class AsyncImageSource
{
    public static NotifyTaskCompletion<ImageSource> FromTask(Task<ImageSource> task, ImageSource defaultSource)
    {
        return new NotifyTaskCompletion<ImageSource>(task, defaultSource);
    }

    public static NotifyTaskCompletion<ImageSource> FromUriAndResource(string uri, string resource)
    {
        var u = new Uri(uri);
        return FromUriAndResource(u, resource);
    }

    public static NotifyTaskCompletion<ImageSource> FromUriAndResource(Uri uri, string resource)
    {
        var t = Task.Run(() => ImageSource.FromUri(uri));
        var defaultResouce = ImageSource.FromResource(resource);

        return FromTask(t, defaultResouce);
    }
}

All this is doing, is creating (and running) a task to download the images in the background and feeding that into the NotifyTaskCompletion.  One caveat here is that even if nothing ever binds to the image, it will still be downloaded.  The ProductViewModel can now expose the IconUrl as an asynchronous wrapper around an ImageSource

public class ProductViewModel : BaseViewModel
{
    private const string _resource = "ShoppingCart.Resources.placeholderImageSmall.png";
    public ProductViewModel(Product product)
    {
        Product = product;
        IconSource = AsyncImageSource.FromUriAndResource(product.IconUrl, _resource);
    }

    public NotifyTaskCompletion<ImageSource> IconSource { get; private set; }

    public Product Product
    {
        get { return GetValue<Product>(); }
        set { SetValue(value); }
    }
}

The ProductsListViewModel will have to expose a list of the ProductViewModel instead of just the raw model which is a shame.  I like binding to the model whenever possible just so I don’t have to worry about passing view models around.  But what can you do?  And now in the view, we bind to the result of the IconSource like so:

<Image Aspect="AspectFill"
       HeightRequest ="75" WidthRequest="75"
       Source="{Binding IconSource.Result}" />

Expectations and Realities

Running up the app my expectation would be to see the loading images when you first go to the product list pages and over the course of 2 to 5 seconds have them change to the correct product images as they are downloaded.  In reality, when I navigated to a page all of the photos were present immediately.  Right away.  No delay.  No loading images.

Happy coding.

Xamarin.Forms: Frames, Event Handlers, and Binding Bugs

To recap, I’m writing a shopping cart app for Windows Phone, Android, and iOS.  The purpose of the app is primarily to let me use Forms.  Each post will build on top of the previous one.

Last time I got some basic binding setup and navigation working.  Today I plan on cleaning up the views a bit so that they look “nice”.  Well nicer.  After that I’d like to show a list of products and let the user drill in and look at details.

Recap and Code

This is the third post in the series, you can find the rest here:

  • Day 0:  Getting Started (blog / code)
  • Day 1:  Binding and Navigation (blog / code)
  • Day 2:  Frames, Event Handlers, and Binding Bugs (blog / code)

The latest version of the code can always be accessed on the GitHub project page.

Cleaning up Login and Main Page

Last time I was focused on functionality.  I was happy to just get the pages to do what I want. Now i want to take a little time and play with the layout a bit.  First on the docket is “MainPage”.  It really isn’t the main page, so I’ll rename that to “WelcomePage”.  This includes the the view model as well.

With that done I want to add some space around all of the text box and button.  Problem is: there’s no “margin” property on any of the controls.  After a little digging, it seems that the only way to add spacing is to wrap each control in its own ContentView and set the Padding property on that.  A slightly simpler approach is to use a Frame instead.  It inherits directly from ContentView and has a default padding of 20.  Despite the fact that this only saves me from setting one property, the fact that it’s in a Frame helps me remember why I’m wrapping the control in the first place.  Let’s wait a few weeks and see if I continue using Frames.

The WelcomePage (né MainPage) now looks like this:

<?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="ShoppingCart.Views.WelcomePage"
             xmlns:local="clr-namespace:ShoppingCart;assembly=ShoppingCart"
             BindingContext="{x:Static local:App.WelcomeViewModel}">

  <StackLayout
    VerticalOptions="Center">
    <Frame>
      <Label Text="Welcome to The Store" Font="Bold, Large" HorizontalOptions="Center" />
    </Frame>

    <Label Text="Login to start shopping" HorizontalOptions="Center" />

    <Frame>
      <Button Text ="Log In" Command="{Binding GoToLoginPageCommand}" HorizontalOptions="Center" />
    </Frame>
  </StackLayout>
</ContentPage>

I also tweaked the welcome text making it bigger and bold as well as adding a call to action to help the user navigate to their next step.  There’s a fair bit you can do with the Font (size, style) property just by providing a comma separated list of values.

The login page got the same spacing treatment, including a nice fat margin around the entire page just so the text boxes don’t sit flush against the right side.  It’s still a little stark so I’ll throw in a touch of color on the title text, just because I can.

<StackLayout VerticalOptions="FillAndExpand" Padding="50">

<Frame Padding="75">
  <Label Text="Login" 
    Font="Bold,Large"
    TextColor="Yellow"
    HorizontalOptions="Center" />
</Frame>

<Label Text="User name" 
  HorizontalOptions="Start" />
<Entry Text ="{Binding Username}" 
  Placeholder ="User name goes here" 
  HorizontalOptions="FillAndExpand" />

<Label Text="Password" 
  HorizontalOptions="Start" />
<Entry Text ="{Binding Password}" 
  Placeholder ="Password goes here" 
  HorizontalOptions="FillAndExpand" />

<Button Text ="Log In" 
  Command="{Binding LoginCommand}" 
  HorizontalOptions="CenterAndExpand" />

</StackLayout>

Now that looks a little bit nicer.

image

Data

Now that the two pages I have look reasonable, I’ll add another.  In order to show some data, I actually need data.  To keep it simple, I start off by creating a list of hard coded C# data.  I have to admit that I got a bit silly here.  At first I tried to hand craft a back log of data.  That got old really fast.  In fact I only got one item defined before I realized I was wasting a lot of time.  Next I decided to grab a list of products (books) from the web and just tweak the data to my needs.  This too proved onerous.  Then I broke down and went to the web to generate all of my data.  I found a great site that even outputs the data in JSON.  It was the first hit on Google.  To process the JSON i nuget and install Newtonsoft’s Json.NET.

I add a ProductLoader and a ProductService class.  The loader simply stores the literal string of JSON and deserializes it on request.  In the future I want to create another implementation that reads the data from disk or the web.  The ProductService doesn’t care where the data comes from, it provides the view models with an interface to query and filter the data.  Because the underlying data will eventually come from a web request, both of these services asynchronously return Tasks. I use Stephen Cleary’s NotifyTaskCompletion in my view model to consume these services.  For a detailed explanation of what’s going on here, take a look at his Patterns for Asynchronous MVVM Applications series.

The data object itself is pretty simple.

public class Item
{
    public string Category { get; set; }
    public string Description { get; set; }
    public string ImageUrl { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
    public string ProductCode { get; set; }
    public int Rating { get; set; }
    public List<string> Tags { get; set; }
}

The Category property lets us show a short list to the user once they log in.  Once they pick a category they see all of the items in that category and then drill down into a specific item.  To accommodate this flow, I’ll add three more pages with corresponding view models:

  • CategoriesListPage/ViewModel
  • ProductsListPage/ViewModel
  • ProductPage/ViewModel

With a bigger app I’d lean towards single instances of each of these pages and using a message broker to update one from the other.  I..e, when a category is clicked on in the CategoriesList page I’d send an “Update List of Products” message and then navigate to the ProductsPage.  But since I already have the convenient App.cs handling all of my interactions between pages, I’ll just squash it into there.  Not ideal for a larger app that I’d like to keep decoupled, but fine for the five pages I currently have.

Lists and DataTemplates

The first thing to tackle is to show the list of categories.  This is similar to traditional two step process in Windows XAML.  Step one:  bind the ItemsSource property to the list.  A quick reminder that the Categories property is a NotifyTaskCompletion<List<string>> which means I need to bind against Categories.Result.  Step two:  define a data template to define how each row looks.  Strictly speaking, since my underlying data is a string, I can skip this step.  Since this is my first time defining a data template in XF, I’ll define one anyway just to make sure it works how I expect.  In my example I’m making the background color red just so I can verify that it’s using my DataTemplate.

<ListView ItemsSource="{Binding Categories.Result}" ItemSelected="OnItemSelected">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <Label Text="{Binding .}" BackgroundColor = "Red" YAlign="Center" Font="Medium" />
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>

Handling Events

You’ll notice in the above definition of my ListView that I’m setting the ItemsSelected event handler.  I’m not binding against the view model here, I’m calling into code behind which then calls into my view model.

public partial class CategoriesListPage
{
    public CategoriesListPage()
    {
        InitializeComponent();
    }

    private void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        var param = e.SelectedItem as string;
        var command = ((CategoriesListViewModel)BindingContext).NavigateToCategory;

        if (command.CanExecute(param))
        {
            command.Execute(param);
        }
    }
}

This is a lot of boilerplate code for handling a click.  The problem is that the ListView doesn’t expose a command I can bind against when an item is selected.  In a traditional Xaml app I’d use the EventToCommand pattern except that it is built on Blend behaviors which aren’t PCL compatible and therefore not Xamarin compatible.

Another option was to subclass the ListView class and expose the command logic that I need.  I might eventually go this route, but I’ll probably need more than a few list boxes in my app to justify it.

Binding Bug in XF

The command for navigating to a category’s page gets a list of all the items for that category and calls into the static App class to get the page to navigate to.

var page = App.GetProductsListPage(items, categoryName);
await _navi.PushAsync(page);

Originally App.cs just updated the properties on the view model and returned the single instance of the ProductsListPage.

public static Page ProductsListPage { get; private set; }

public static Page GetProductsListPage(List<Item> items, string title)
{
    if (string.IsNullOrWhiteSpace(title)) title = "Products";

    ProductsListViewModel.Products = items;
    ProductsListViewModel.Title = title;
    return ProductsListPage;
}

This relies on the binding to update the view when something has changed and INotifyProperty.PropertyChanged is raised.  The first time this is called it works just fine.  It fails on all subsequent calls.  After a lot of debugging and assuming that I was wrong I found a recent post on Xamarin’s forums explaining that there is a bug where the UI is not updated when a bound value is changed.  Note that this only effects values that are updated in the view model updating on the view; the other way works just fine.  Updating a value in the view (like a text entry) correctly updates the bound value in the view model.  This is why my login page worked just fine.

Xamarin has released a fix for this bug, but as of writing this it is in a pre build of XF.  I tried to use it but kept getting runtime DLL errors.  I tried several times before having to give up on this as an immediate solution.  I will say that this may have just been an issue with user error since it was close to 1 AM at this point.

In my specific case, there was no reason that I had to reuse the same view.  Simply recreating the view every time I wanted to display it was simple enough.

public static Page GetProductsListPage(List<Item> items, string title)
{
    if (string.IsNullOrWhiteSpace(title)) title = "Products";

    ProductsListViewModel.Products = items;
    ProductsListViewModel.Title = title;
}

Summary

Today I was able to clean up some of the views using the Frame control to provide margins.  I had to resort to two workarounds, one for routing events to commands in code behind the other for updating the view when a bound value has changed.

I’m not sure what I want to tackle next week.  Perhaps reading from the file stream?  Maybe fleshing out the products view a bit so I display an image to go with the product?

Until then, happy coding.

Xamarin.Forms: Binding and Navigation

To recap, I’m writing a shopping cart app for Windows Phone, Android, and iOS.  The purpose of the app is primarily to let me use Forms.  Each post will build on top of the previous one.

Last time we did little more than get our feet wet.  The plan for today is to create a page with data binding  At this stage of the app, that sounds like a login page to me.

An aside.  It got rather tiring saying “Xamarin.Forms” all the time and I’m not quite comfortable just calling it “Forms” because I keep thinking back to WinForms whenever I do.  So I’m just going to go the abbreviation route and call it XF.  The abbreviation has the benefit of starting with an “X” and those are just cool.

Recap and Code

This is the second post in the series, you can find the rest here:

  • Day 0:  Getting Started (blog / code)
  • Day 1:  Binding and Navigation (blog / code)

The latest version of the code can always be accessed on the GitHub project page.

Binding

Before I’m able to do anything fancy, I need to figure out how to do some basic binding.  To test this out, I create a basic view model with one property that returns some constant text.

public class MainViewModel
{
    public string Message {get { return "Hello World";}}
}

I update the view to simply bind to this message now instead of hard coding the text in the XAML.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ShoppingCart.Views.MainPage">
    <Label Text="{Binding Message}" HorizontalOptions="Center" />
</ContentPage>

For now, I’ll just set the BindingContext in the page’s constructor.

public partial class MainPage : ContentPage
{
    public MainPage(MainViewModel vm)
    {
        this.BindingContext = vm;
        InitializeComponent();
    }
}

All that’s left is to pass in a new view model when creating the page.

new MainPage(new MainViewModel())

Firing up the emulator, this works out of the gate.  Nice.  Time to move on to something a little more difficult.

The Main Page

I don’t want the login page to be the first page of the app.  I think some sort of splash screen or welcome message would make more sense.  For now It will simply just have some text and a button that’ll take you to the login page.  I’ll add the standard Command=”{Binding GoToLoginPageCommand}” now and wire it up next.

<?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="ShoppingCart.Views.MainPage"
             xmlns:local="clr-namespace:ShoppingCart;assembly=ShoppingCart"
             BindingContext="{x:Static local:App.MainViewModel}">

  <StackLayout
    VerticalOptions="Center">
    <Label Text="Welcome to the main page." HorizontalOptions="Center" />

    <Button Text ="Log In" Command="{Binding GoToLoginPageCommand}" HorizontalOptions="Center" />
  </StackLayout>
</ContentPage>

Now that I know I need to bind to a command, I add the MainViewModel.  The command adds some complexity for two reasons.  First it’s a command so I need to either implement ICommand or find an already ready implementation.  There’s nothing that I could find in XF that implements ICommand for me and I don’t want to bring in an outside framework like MvvmLight just yet so I go ahead and add add a simple implementation of ICommand.  It’s so simple that I even named it SimpleCommand.cs.  I’m not really sure if this will stay long term, but it’ll do the job for now.

The second bit of complexity isn’t as easy.  It’s the fact that I don’t know how to do navigation in XF.  So it’s time for some research.  To the LIBRARY!

Figuring Out Navigation

According to the doco, all you need to do is wrap your ContentPage in a Navigation page.  This is as simple as

new NavigationPage(new MainPage())

Then in your page you can access the Navigation property.  After playing with this property a bit I learned that how it works depends on your platform.  On Windows Phone it was non null and worked regardless of whether or not you created a NavigationPage.  Android was less forgiving.  One nice touch was that as soon as you wrap your droid page you get the ActivityBar back button.

Playing around with the Navigation property on the page on both Windows and Android, I found it to be buggy.  I set up a simple pair of pages with one button each.  The first page would merely navigate to the second page.  The second page would just pop the stack and return to the first.  With some experimenting it looked to me that the XF infrastructure worked best if you always used the same exact instance of INavigation.

In my opinion, there’s a problem with navigation living in the page.  Navigation is important business logic and business logic should not live in the view layer.  I don’t want to fight the infrastructure too much but if at all possible, I’m going to want to see what can be done to move navigation to the view model layer.

With this knowledge and my desire to abstract the navigation property out to the view model, I created my own wrapper navigation service.

public class NavigationService : Xamarin.Forms.INavigation
{
    public INavigation Navi { get; internal set; }

    public Task<Page> PopAsync()
    {
        return Navi.PopAsync();
    }

    public Task<Page> PopModalAsync()
    {
        return Navi.PopModalAsync();
    }

    public Task PopToRootAsync()
    {
        return Navi.PopToRootAsync();
    }

    public Task PushAsync(Page page)
    {
        return Navi.PushAsync(page);
    }

    public Task PushModalAsync(Page page)
    {
        return Navi.PushModalAsync(page);
    }
}

Very simply, it directs all calls to an internal implementation.  Again, the static App class is responsible for coordinating the creation of these classes

NavigationService navi = new NavigationService();
MainViewModel = new MainViewModel(navi);

MainPage = new NavigationPage(new MainPage());

navi.Navi = MainPage.Navigation;

Back to the MainViewModel

Now that we’ve solved the problems of commands and navigation, it’s pretty simple to finish off our MainViewModel.

public class MainViewModel
{
    private readonly INavigation _navi;

    public MainViewModel(INavigation navi)
    {
        _navi = navi;
    }

    public ICommand GoToLoginPageCommand
    {
        get { return new SimpleCommand(() => _navi.PushAsync(App.LoginPage)); }
    }
}

I left the creation of the login page in the App.  This way all my page creation can live in one place.

The Login Page

The login page and view model model are pretty simple.  Fields for username and password, and a button to submit.  Upon “successfully” logging in we’ll just return back to the  the main page.  If there’s a failure then we display a message box.

Like navigation, displaying a message box is tightly coupled to the page.  I wound up wrapping it up in my Navigation class in a similar fashion as navigation.  It’s not really the best spot for it, but it cut down on the number of classes and interfaces i was creating.  Also, it was a fast addition.  Given the size of the project I don’t really have a problem with it now, but I foresee it being moved out at some point.

Here’s what the navigation interface and implementation look like now:

public interface INavigationService : INavigation
{
    Task<bool> DisplayAlert(string title, string message, string accept, string cancel = null);
}

public class NavigationService : INavigationService
{
    public INavigation Navi { get; internal set; }
    public Page myPage { get; set; }

    public Task<Page> PopAsync()
    {
        return Navi.PopAsync();
    }

    public Task<Page> PopModalAsync()
    {
        return Navi.PopModalAsync();
    }

    public Task PopToRootAsync()
    {
        return Navi.PopToRootAsync();
    }

    public Task PushAsync(Page page)
    {
        return Navi.PushAsync(page);
    }

    public Task PushModalAsync(Page page)
    {
        return Navi.PushModalAsync(page);
    }

    public Task<bool> DisplayAlert(string title, string message, string accept, string cancel = null)
    {
        return myPage.DisplayAlert(title, message, accept, cancel);
    }
}

Wiring up ViewModels

A pattern I have always liked from the MvvmLight toolkit is setting up the binding to the view model directly in the view’s XAML.  I had to tweak the default MvvmLight template a bit to get this to work, but in the end it wasn’t pretty simple.  In the view, create a static binding to a property exposed by the App class.  This could be any class, but I went with the App class since it is already being used as a static resource for all of the views anyway.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ShoppingCart;assembly=ShoppingCart"
             BindingContext="{x:Static local:App.LoginViewModel}"
             x:Class="ShoppingCart.Views.LoginPage">
  <!-- Code removed for brevity-->

</ContentPage>

This lets us simplify App.cs just a little bit, now that we don’t have to pass in the view models to the views.

public static class App
{
    public static MainViewModel MainViewModel { get; set; }
    public static LoginViewModel LoginViewModel { get; set; }

    static App()
    {
        ILoginService login = new LoginService();
        NavigationService navi = new NavigationService();

        MainViewModel = new MainViewModel(navi);
        LoginViewModel  = new LoginViewModel(login, navi);

        MainPage = new NavigationPage(new MainPage());
        LoginPage = new NavigationPage(new LoginPage());

        navi.Navi = MainPage.Navigation;
        navi.myPage = MainPage;
    }

    public static Page LoginPage { get; private set; }
    public static Page MainPage { get; private set; }
}

Summary

This is pretty much it for this week.  I’ve added binding, commands, and navigation as well as wired up the view models.  Next week I’ll flesh out the products pages and try to actually add the shopping cart.  Until then, happy coding.

Xamarin.Forms: Setup

This will be the first in a series where I create a shopping cart application using Xamarin.Forms  While I have experience using Xamarin and MVVMCross to create applications, I have never used Forms before.  This series is intended as a journal of my learning experience where I will point out stumbling blocks and tricks I pick up along the way.

Setting out, I plan to build a cross-platform shopping cart application using XAML using the MVVM design pattern.  I’ll focus my tests on Windows Phone because it’s much easier and faster to test but I will also verify that the app works on Android whenever it makes sense.  Sadly I don’t have the equipment necessary to test on iPhone.

The source code for this article can be downloaded from GitShoppingCart-Day0.zip

Quickly, What is Xamarin.Forms?

Traditionally Xamarin has let you write a WindowsPhone, iOS, and Android apps in C#, letting you share all app logic.  You would only need to rewrite your views for each platform, using the device specific controls and paradigms.

With Forms is Xamarin has added a cross platform UI framework.  It allows you to define your UI with device agnostic names for common controls.  For instance, in Forms you’d use an Entry object instead of the WindowsPhone TextBox or the Android EditText.  When run, the app still renders 100% native controls.  So even though they share a common UI definition, buttons on  WindowsPhone look like WindowsPhones butons; buttons on Android look like Android buttons; Buttons on iPhone look like iPhone buttons.

Getting Started

With all the preliminaries out of the way, let’s create our first app.  Fire up Visual Studio (you can use Xamarin Studio if you like, but VS is my home). Go to File-> New-> Project and pick Blank App (Xamarin.Forms Portable).  You can use the filter in the top right to find the project template more easily.  I’m calling it ShoppingCart.

image

This will take a second to generate 4 projects for you:

  • ShoppingCart
  • ShoppingCart.Android
  • ShoppingCart.iOS
  • ShoppingCart.WindowsPhone

image

ShoppingCart is your main project.  It is referenced by the other three.  At this point you can set any of the device projects (ShoppingCart.Android, ShoppingCart.iOS, ShoppingCart.WindowsPhone) as the startup object and deploy the app to your device or emulator.

ShoppingCart only has one code file in it, App.cs. All this does is create an instance of a Page and return it.

public class App
{
    public static Page GetMainPage()
    {
        return new ContentPage
        {
            Content = new Label
            {
                Text = "Hello, Forms !",
                VerticalOptions = LayoutOptions.CenterAndExpand,
                HorizontalOptions = LayoutOptions.CenterAndExpand,
            },
        };
    }
}

So it seems the Page class is the base of every view, analogous to a WindowsPhone PhoneApplicationPage, iOS UIViewController, or Android  Activity.  The device specific startup logic grabs the Forms Page object and sets it as it’s startup object.  Pretty straight forward.

Starting out with XAML

All I want to accomplish today is to change the definition of that view from C# to XAML.  In the ShoppingCart project, I’ll create a new folder called “Views” an add a Forms.Xaml Page named “MainPage”

image

image

This is a new item template that you get with the Forms projects.  Similar to the PhoneApplicationPage, it’s a XAML file with a code behind.  You can see that it inherits from ContentPage, the same type that App.GetMainPage creates.

At this point, I’m starting to notice that Visual Studio is starting to slow down. Switching between tabs and making edits to the .xaml file is sluggish.  Now, this may just be my machine.  It’s fast, but only has 4GB or RAM.  It’s also been acting up in other ways lately and I’ve been meaning to reformat.  Since I don’t seem to be getting intellisense in the xaml file, I’ll just switch to an alternative text editor instead.  I’ve already set up VS to open files in vim when I hit Ctrl-Alt-V so this isn’t really a big annoyance for me.

This view is supposed to be a simple copy of the one defined in App.cs, so I’ll delete the default Label they give me from the template and replace it with one with some static text.  Although, it is nice to note that the sample uses a simple binding for the text property.  I wonder where we set what we bind against, but I’ll worry about that later.

<?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="ShoppingCart.Views.MainPage">
  <Label Text = "Hello, XAML Forms!"
         VerticalOptions = "CenterAndExpand"
         HorizontalOptions = "CenterAndExpand" />
</ContentPage>

OK, my first bit of Form xaml done and it wasn’t too painful.  Now to wire it up.  Going back to App.cs, instead of creating a new ContentPage, I new up an instance of MainPage and return that.

public static Page GetMainPage()
{
    return new MainPage();
}

Firing up the emulator, it looks like it works.  I changed the text in the label ever so slightly to make it easy to ensure that I know that I’m seeing my changes.

So that’s enough for me to call it a victory and go reward myself with some XBox One.

The source code for this article can be downloaded from GitShoppingCart-Day0.zip.  Note how it is stunningly close to the default template.  Not much changed.

Building iOS views in code

The Problem

I started doing iOS development in Xamarin in C# (one look at Objective-C was enough for me).  Writing C# for iOS in Xamarin Studio is where I spend most of my days.  Occasionally I switch over to Windows to lather in the Visual Studio goodness, however, Xamarin Studio is mostly enjoyable.  When it comes to creating UIs in iOS, the standard approach is to fire up Xcode, build your UI in the WYSIWYG editor, wire up your outlets, save your changes, and hope Xamarin Studio picks up your changes.  It’s a fairly arduous process, but it works.

My coworkers don’t have access to an instance of Xcode (there’s only one MacBook in my team).  This means, they can’t make any UI changes.  On top of that, I don’t like building UIs in the Xib interface builder.  I find it rather confusing and overkill for my needs.  I’m also the type of person who would rather build my UI out in Photoshop, and translate it directly to code.  I guess that’s the web developer in me.

The Solution

With iOS 6 came Auto Layout – the ability to create relationships between UI elements using constraints.  Once you add all your elements to the parent element, you define the relationships between each of the objects.  The platform will then draw the UI for you, honoring all of your constraints (if you specified them correctly).

Let’s say, I want to build the following view.  Here’s what the code looks like (come back when you’re finished throwing up):

OldConstraintsParentChild

That just sucks.

Another solution

XibFree is a really nice solution.  It does what it says – let’s you build UIs without a XIB.  It was the first solution I played around with.  I’m not going to go into too many details about it (ironically, the documentation is what I find most lacking).  It’s a lot less wordy and mostly uses the Android XML language.  If you’re doing cross platform development AND you’re coming from Android, the learning curve is not as steep.

I guess my biggest issue with XibFree was animating, showing, hiding, etc.  For the most part, it worked fine.  As my interface got more and more complicated, it became difficult to debug some of these issues.

My favorite solution

If you aren’t familiar with @slodge or MvvmCross, get ready to have a good time.

In a mere couple hours, Stuart Lodge changed me life.  To see how, read hist post (http://slodge.blogspot.com/2013/07/playing-with-constraints.html).  In short, he’s build a library which allows you to use a declarative way to define your views using the native NSLayoutConstraints.  Score!

It’s so easy to use, let’s make the example a little bit more complicated.

ConstraintsParentChild

   

And another example.

ConstraintsSameLeftBelow

I know you’re excited.  Now go download the library and develop away.  It’s available on GitHub – https://github.com/MvvmCross/MvvmCross.

What can you do

Like XibFree, the documentation is a little lacking.  However, you have the source.  So, let’s see what we can do with this library.

  • child.AtTopOf(parent[, margin]) – attaches the top of the child’s frame to the top of parent’s frame
  • child.AtLeftOf(parent[, margin]) – attaches the left side of the child’s frame to the left side of the parent’s frame
  • child.AtRightOf(parent[, margin]) – attaches the right side of the child’s frame to the right side of the parent’s frame
  • child.AtBottomOf(parent[, margin]) – attaches the bottom of child’s frame to the bottom of the parent’s frame
  • view1.WithSameLeft(view2) – attaches the left value of view1 (view1.Frame.X) to the left X value of view2
  • view1.WithSameRight(view2) – attaches the position of the right side of view1 (view1.Frame.Right) to the same right value as view2
  • view1.WithSameTop(view2) – attaches the top Y value of view1’s frame (view1.Frame.Y) to the top Y value of view2
  • view1.WithSameBottom(view2) – attaches the bottom of view1’s frame (view1.Frame.Bottom) to the bottom as view2
  • view1.WithSameCenterX(view2) – attaches the horizontal center of view1 to the horizontal center of view2
  • view1.WithSameCenterY(view2) – attaches the vertical center of view1 to the vertical center of view2
  • view1.WithSameWidth(view2) – attaches the width of view1 to the width of view2
  • view1.WithRelativeWidth(view2[, scale]) – attaches the width of view1 to the width of view2, with an optional scale factor
  • view1.WithSameHeight(view2) – attaches the height of view1 to the height of view2
  • view1.WithRelativeHeight(view2[, scale]) – attaches the height of view1 to the height of view2, with an optional scale factor
  • view1.Below(view2[, margin]) – attaches the top value of view1 to the bottom value of view frame
  • view1.Above(view2[, margin]) – attaches the bottom value view1 to the top value of view2
  • view1.ToRightOf(view2[, margin]) – attaches the left value of view1 to the right value of view2
  • view1.ToLeftOf(view2[, margin]) – attaches the right value of view1 to the left value of view2
  • view1.FullWidthOf(view2[, margin]) – attaches the left and right values of view1 to view2
  • view1.FullHeightOf(view2[, margin]) – attaches the top and bottom of view1 to view2

Headers and Footers on an MvxListView

Full source for this post can be found on GitHub:  HeaderedGridView

Last week I posted about adding a header to a GridView.  Today I’ll be discussing how to add a header (and footer!) to a MvxListView.  The MvxListView is a data-binding friendly ListView from MvvmCross.  Adding a header here is a little different because we need an instance of HeaderViewListAdapter that implements IMvxAdapter .  Other than that, the code should be very familiar.

Requirements

Just so it is clear what we are building, here are my requirements for this control:

  1. Ability to add a header and footer to the MvxListView in xml markup
  2. The header is to be laid out inline with the rest of the items, at the top
  3. The footer is to be laid out inline with the rest of the items, at the bottom
  4. The header and footer need to scroll with the rest of the content, i.e., they are not always visible
  5. The header and footer must be able to use MvvmCross bindings

Some quick screenshots from the sample project will help us understand what this should look like.

top.png

The list is scrolled to the top with purple header visible

middle.png

Shows the list at some point in the middle when neither header nor footer is visible

bottom.png

The list scrolled all the way to the bottom with the green footer visible

Code

Full source for this post can be found on GitHub:  HeaderedGridView

The MvxListView assumes that the adapter it has implements IMvxAdapter.  We can create a simple wrapper class that inherits from HeaderViewListAdapter and implements that interface.  The constructor will accept the list of headers and footers like the base class in addition to accepting an IMvxAdapter to wrap.  All of the interface methods for IMvxAdapter can then be passed down to the internal adapter.

In the snippet of HeaderMxAdapter above we have two constructors.  The first can be used if you do not want to add a footer.  It simply calls into the second passing an empty list of footers to add to the adapter.  The only other thing the constructor does is to squirrel away the adapter in a private field for later use.

The implementation for DropDownItemTemplateId is simple and indicative of the rest of the methods in the class.  It merely calls into that squirreled away adapter, calling its implementation of DropDownItemTemplateId.  The rest of the methods are exactly the same and have been omitted for brevity.

Next step is to add a pair of attributes to use for our header and footer.  This is exactly the same as the headered grid view and is done in attrs.xml.

Some boiler-plate code in MvxListViewWithHeader will read these values so we know what views to use for the header and footer.  Like last time, I’m using some helper classes to do the parsing.  They are included in the project.

Next we need to create the views for the header and footer .

First we check if the id is the default header id, if it is then we don’t have a view defined in the xml, and we just return null.  After that we get the current binding context and use it to inflate our view.  This is the magic that lets us bind within our header and footer.

Once we have the view, we need to wrap it in a list of FixedViewInfo which is what the HeaderMxAdapter expects in its constructor.

Nothing earth shattering here.  If the view is null, return an empty list, otherwise construct the FixedViewInfo and add it to the list.  Returning an empty list allows us to specify only the header, only the footer, or neither without causing any errors.

A couple of helper methods make help to make it clear and concrete what GetFixedViewInfos does.

All of this is called from the constructor which creates the MvxAdapter and wraps it in our new HeaderMvxAdapter.  It then set the adapter property in the base class.

The constructor is also responsible for reading in the item template id which the MvxListView uses to display the individual items in the list.

Using the Control

You would use the MvxListViewWithHeader the same way as a MvxListView.  The only difference is that you can now optionally specify a header or footer attribute which would point to another layout.  The following is taken from the FirstView in the sample.

The header and footer layout in the sample are very simple.  They are just a TextView with the text property bound to the view model.  Here is the header layout, but the footer is almost identical:

Future Improvements

Like the headered grid view, this implementation only allows a single header. If we had need for multiple headers we could copy the  onFinishedInflate method from ListView.  It collects all the child layouts for the list view and adds them to the list of headers.

Happy Coding

Headered Grid View in MvvmCross. Now with bindings!

Full source code for this article can be downloaded on GitHub:  HeaderedGridView.

For the easy import feature of Yarly, I needed to create a view that would easily allow a user to select an existing photo to import into the app or to take new photo. A grid view of photos from the camera roll but with the first item as a button that would load the camera would serve nicely for this use case. See the screen shot below of an early version of the UI:

Yarly Screen Shots 2014-04-20_194747_242000

This reminded me of the AddHeaderView method available on ListView. With that as a guide, I decided to add similar functionality to the GridView.  Since I’m using MvvmCross, I also want to make sure that I can use bindings in the header control. While I’m at it, having to explicitly call AddHeaderView in my activity code is useful, but I’d much rather to be able to do this in markup. 

Requirements

To sum up the above requirements:

  1. Ability to add a header to a GridView in xml markup
  2. The header is laid out inline with the rest of the items in the GridView
  3. The header scrolls with the rest of the content, i.e., it is not always visible
  4. The header must be able to use MvvmCross bindings

Code

A full sample project can be downloaded from my GitHub repo:  HeaderedGridView.

In attrs.xml, add an attribute to use for our header. 

<!-- attrs.xml --> <declare-styleable name="GridView">

   <attr name="header" format="reference" /> </declare-styleable>

In the HeaderedGridView, all we need to do now is check for the presence of this attribute, and if it exists, inflate the view.  Reading the header id is straight forward processing of the IAttributeSet.  I use some helper classes to iterate and dispose of the attributes in a more C# way.  The details aren’t very important, but the relevant classes are included in the sample solution.  The MvvmCross class MvxAndroidBindingContextHelpers can return the current binding context which can be used to inflate and bind the header at the same time.

// HeaderedGridView.cs private void ProcessAttrs(Context c, IAttributeSet attrs) {

     _headerId = DEFAULT_HEADER_ID;

     using (var attributes = c.ObtainDisposableStyledAttributes(attrs, Resource.Styleable.GridView))

     {

         foreach (var a in attributes)

         {

             switch (a)

             {

                 case Resource.Styleable.GridView_header:

                     _headerId = attributes.GetResourceId(a, DEFAULT_HEADER_ID);

                     break;

             }

 

         }

     } } private void LoadHeader() {

     if (_headerId == DEFAULT_HEADER_ID) return;

     IMvxAndroidBindingContext bindingContext = MvxAndroidBindingContextHelpers.Current();

     _header = bindingContext.BindingInflate(_headerId, null); }

Now that we have a header, we can wrap our current adapter in the HeaderViewListAdapter.  As the name implies, this is the exact same adapter used by the ListView.  It handles knowing when and where to show the header.  In my sample code, I have the grid create the adapter directly, but this can work just as well if an adapter is passed in from outside.

// HeaderedGridView.cs

private IListAdapter GetAdapter() {

     var headerInfo = GetHeaders();

     ICursor cursor = ImageAdapter.CreateCursor(Context);

     IListAdapter adapter = new ImageAdapter(Context, cursor);

 

     if (headerInfo != null)

     {

         adapter = new HeaderViewListAdapter(headerInfo, null, adapter);

     }

     return adapter; }

So I don’t have to hard code sizes and so the header matches the rest of the items in the grid, I set the height and width once the grid is being laid out.  In the OnMeasure method we check if the header isn’t null, and if the ColumnWidth doesn’t match the previous column width we saw.  Caching the width and testing this prevents us from setting the layout parameters when we don’t have to; OnMeasure is called multiple times.

// HeaderedGridView.cs protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) {

     base.OnMeasure(widthMeasureSpec, heightMeasureSpec);

 

     if (_header != null && base.ColumnWidth != _cachedColumnWidth)

     {

         _cachedColumnWidth = base.ColumnWidth;

         _header.LayoutParameters = new ViewGroup.LayoutParams(_cachedColumnWidth, _cachedColumnWidth);

     } }

Now all we need to do is include our grid in a layout.   It’s almost exactly the same as the regular GridView, except we can now optionally specify a header.  This is from the FirstView layout in the sample.

<!--FirstView.axml--> <HeaderedGridView

   android:layout_width="fill_parent"

   android:layout_height="fill_parent"

   android:layout_weight="1"

   android:numColumns="3"

   android:verticalSpacing="10dp"

   android:horizontalSpacing="10dp"

   android:stretchMode="columnWidth"

   android:gravity="center"

   android:fastScrollEnabled="true"

   android:background="#000000"

   local:header="@layout/gridheader" />

The gridheader layout is just a simple layout with a single image button button.  Note that we are binding the click of the button to the ClickCommand in our view model.

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=http://schemas.android.com/apk/res/android

     xmlns:local=http://schemas.android.com/apk/res-auto

     android:orientation="vertical"

     android:layout_width="fill_parent"

     android:layout_height="fill_parent"

     android:padding="5dp">

     <ImageButton

         android:layout_width="fill_parent"

         android:layout_height="fill_parent"

         android:background="#90C53E"

         android:src="@drawable/camera"

         local:MvxBind="Click ClickCommand" /> </LinearLayout>

Firing up the sample solution and we should see something similar to:

Yarly Screen Shots 2014-04-21_184439_262000 

Future Improvements

My implementation restricts me to only being able to add one header.  While one header is currently good enough for me, if I wanted to expand it add more, I could emulate ListView a bit more.  Specifically the onFinishedInflate method which adds child layouts as a list of headers.  Of course, I could also add an explicit AddHeaderView method that could be called multiple times.

I’ve ignored footers entirely.  Again, this is just because I don’t currently have any need for a footer.  They could be added easily enough following the same pattern as headers.

Happy Coding.

Setting up Xamarin Studio and MonoDroid

I’ve spent the past few hours working through a fresh install of Xamarin Studio.  While most of it is really easy, there are some major gotchas.  The best thing about the process is that it is one installer for everything including dependencies.  The download page misleadingly asks you what level license you want when.  Ignore that.  It has nothing to do with the installer or the license you actually wind up using.  If you’re just trying it out there’s a 30 day trial license that gets you access to all of the features.

The installer pulls down all of the Android development tools as well:  the emulator, the SDK manager, java samples.  Everything.  After the installer finishes you are ready to write your first android app.  Almost.

Hello world in Xamarin Studio

First thing I did was fire up Xamarin Studio (their IDE) and create a new Android Application.  Out of the box this is a “Hello World” app with a single button on a page.  Couldn’t get much simpler.  It didn’t compile for me.  I got:

‘Error MSB4018: The “Aapt” task failed unexpectedly’ on new Android Application. No code added.

The solution here was fairly simple.  Go to the Android SDK Manager (it should be in your start menu/screen) and install all of the updates.  Just click the install button on the bottom right.

image

Once that’s done you can go back and run your app.  It will prompt you to launch an emulator and deploy the app automatically.  One thing to note here is that the emulator can take a while (minutes) to start up.  Even worse, once it is fully started it stays on the ANDROID loading screen waiting for you to hit a button.  There’s no way for you to know it’s ready for you unless you go back and poke it every now and then.

image

Debugging in Visual Studio

While Xamarin Studio seems to be a decent IDE and you can debug an application from there (breakpoints, watch screens, variable evaluation on mouse hover, threads list, etc.) I am definitely more comfortable with Visual Studio.  If you don’t have a trial (or real) license yet, you will be prompted for it when you open up a Xamarin project in Visual Studio, either by opening the solution file you created in Xamarin Studio or by creating a new Android project directly in Visual Studio.  That’s where it stops being easy though.  The first thing you might notice is that when you try to debug the application you get the following error:

The application could not be started. Ensure that the application has been installed to the target device and has a launchable activity (MainLauncher = true).

Additionally, check Build->Configuration Manager to ensure this project is set to Deploy for this configuration.

The error message is right, the application wasn’t installed on the “target device” (the emulator).  If you created the project in Xamarin Studio you need to explicitly tell VS that you want to deploy the app the phone before debugging.  Go to the Configuration Manager and ensure that Deploy is checked off for your project.

image

image

If you created the project in Visual Studio, you shouldn’t have this problem.  it seems to only happen when you create the project in Xamarin Studios first.

Now that the application is deployed to the phone there is still one more hurdle before you can debug from Visual Studio.  Whenever I tried to attach to a running virtual machine the debugger would deploy the app and chug along for a little while.  Eventually it would quietly die and disconnect.  The application wouldn’t load in either the debugger or emulator.  I didn’t see anything in the log file that helped point to the problem.   Eventually I got lucky and determined that I could connect if the virtual machine was running an Intel Atom (x86) processor then everything worked.  My assumption is that Visual Studio doesn’t know how to compile for ARM.  If you look at the project properties for an Android app in Visual Studio, there is only x86 and x64:

image

Xamarin’s site has some pretty easy to follow instructions on how to configure an x86 emulator.  The main task is to install Intel’s HAXM software.  What they skip over is that you can’t install this if you have Microsoft Hyper-V installed.  Hyper-V is Microsoft’s hardware virtualization stack that is used by the Windows Phone Emulator.  Ben Armstrong has some really good instructions on how to create a profile in Windows that will disable Hyper-V at startup.  They boil down to two commands to run on the command line and a restart:

bcdedit /copy {current} /d "No hypervisor"
bcdedit /set {GUID From the previous command} hypervisorlaunchtype off

For the GUID in the second command, copy the output of the first command including the brackets.  It should look something like this:  {7d067ad2-16ce-11e2-a059-9b573bf76ddc}.  Then just restart the computer and select “No hypervisor” when prompted at the boot screen.  From here you can continue through the instructions on how to configure an x86 emulator.

There’s a trade off here.  You won’t be able to switch between debugging a Windows Phone application and an Android application without restarting your computer, but on the other hand, because it uses hardware level virtualization, the x86 emulator is significantly faster than the ARM versions.

UPDATE:

After running these two commands a couple of times, I got lazy and wrote a powershell script to do everything in one go:

# This script makes a copy of the current boot record and disables Hyper-V
# The next time the computer is restarted you can elect to run without Hyper-V
 
$output  = invoke-expression 'bcdedit /copy "{current}" /d "Hyper-V Disabled"'
$output -match '{.*}'
$guid = $matches[0]
$hyperVCommand = 'bcdedit /set "' + $guid + '" hypervisorlaunchtype off'
invoke-expression $hyperVCommand

Summary

Here’s a quick run down of the steps covered above

  1. Download and install Xamarin Studio
  2. Install all the updates in the Android SDK Manager
  3. Make sure Visual Studio knows to deploy the app before trying to debug
  4. Disable Hyper-V
  5. Configure an x86 emulator