30 July 2014

Sharing code between a Xamarin Forms/MVVMLight app and EF-code first backend using Shared Reference Project Manager

Disclaimer

I am in the very early early stages of toying with Xamarin and it may well be that whatever I am doing here, is not the smartest thing in the world. This is a much as a report of my learning (may ‘struggle’ is a better word) as how-to. But what I describe here works – more or less – although it was a mighty hassle to actually get it working.

The objective

While I was having my first trials with Xamarin stuff, I turned to Entity Framework Code First because, well, when setting up a backend I am lazy. Without much thinking I made the models, using data annotations, and soon found out I had painted myself into a corner with a model that (very simplified) looks like this

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace DemoShared.Models
{
   [Table("Pictures")]
    public class Photo
    {
      public long ID { get; set; }
      
     [Required]
      public string Name { get; set; }
    }
}

imageGuess what - data annotations don't work in PCL. Now what? Make a shadow class library for use on the client? That kind of went against my principles. So I decided to use the Shared Reference Project Manager.  This is a Visual Studio extension that can make basically any project shared, in stead of only between Windows Phone 8.1 and Windows 8.1 You can get it here.

Setting up the initial application

Using this tutorial by Laurent Bugnion I did set up my first Xamarin MVVM application. I created an app "DemoShared" and used the tutorial it up to the point where he starts making a new new xaml page (“Creating a new XAML page”).

Try to build the project. If the Windows Phone project fails with “The 'ProductID' attribute is invalid.. “ (etc), manually open it’s Properties/WMAppManifest.xml, for instance with NotePad, find “ProductID and “PubisherID” and place the generate GUIDs between accolades. This is a bug the Xamarin project template that I already reported.image

Basic setup of the backend

  • File/New Project/Web/ASP.Net Web application (it’s the only choice you have)
  • Choose a name (I chose DemoShared.Backend) and hit OK
  • Choose “Web Api” and UNSELECT “Host in the cloud”
  • Go to the NuGet Package manager and update all the packages, because a lot of them will be horribly outdated. Hit “accept” or “yes” on any questions
  • Delete the all folders except “App_Data”, “App_Start” and “Controllers” because we don’t need them
  • Delete BundleConfig.cs from App_Start, and remove the reference to it from Global.asax.cs as well
  • Add a (.NET) class library DemoShared.DataAccess
  • Install NuGet Package “EntityFrameWork” in DemoShared.Backend and DemoShared.DataAccess
  • Create a project DemoShared.Models of type Shared Project (Empty) of type Visual C#:

image

  • Right-click the DemoShared (Portable) project, select Add, then “Add Shared Project reference”, then select “DemoShared.Models
  • Repeat this procedure for DemoShared.DataAccess.
  • Also add a reference to System.ComponentModel.DataAnnotations to DemoShared.DataAccess.
  • Add DemoShared.DataAccess as a reference to DemoShared.Backend

Re-defining the models

The key point of this whole exercise is to re-use models. For one model class this is quite some overkill, but if you have a large collection of models, things becomes quite different. So anyway. I redefined the model class as follows:

#if NET45
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#endif

namespace DemoShared.Models
{
#if NET45
   [Table("Pictures")]
#endif

  public class Photo
  {
    public long ID { get; set; }

#if NET45     
     [Required]
#endif
    public string Name { get; set; }
  }
}

Now in order to make this compile work the way it is intended on server, you will need to add the conditional compilation symbol “NET45” to all configurations of DemoShared.DataAccess

image

And then it compiles both into PCL and into the DataAccess project – without the attributes in the first, but with the attributes the second. Remember, this is just a really nifty formalized way of ye olde way of file linking.

Kick starting the Entity Framework

Following this tutorial – more or less, I added the following class to the DataAccess project:

using System.Data.Entity;
using DemoShared.Models;

namespace DemoShared.DataAccess
{
  public class DemoContext : DbContext
  {
    public DemoContext()
      : base("DemoContext")
        {
        }

    public DbSet<Photo> Photos { get; set; }
  }
}

And then to the web.config I added this rather hopeless long connection string:

<connectionStrings>
  <add name="DemoContext" connectionString="Data Source=(localdb)\v11.0;AttachDbFilename=|DataDirectory|DemoDb.mdf;Initial Catalog=DemoDb;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>

Rebuild the project. Now go to the Backend Controller folder, right click Add/Controller, select “Web API 2 Controller with actions, using Entity Framework” and in the following dialog, select the Model and Data Context class as displayed to the right

imageimage

imageNow if you set “DemoShared.Backend” as start-up project, set it’s startup URL to “api/photos” and start the project, you will automatically get a database “DemoDb” in “App_Data”.Is EF code first cool or what? And my data annotations are used correctly – the Photo type is stored in the “Pictures” table, just as I wanted.

image

Now I manually entered some data in the tables to get something to show, but of course you can also write an initializer like the EF tutorial describes, or write a separate project that prefills the the database. This is what I usually do, and that’s why I have put the DemoContext in a separate assembly and not in the web project – to be able to reference it form another project.

And now finally, to the Xamarin app

Adding the view model

First of all – start the NuGet package manager and add Newtonsoft Json.NET to DemoShared (Portable).

Then, add a “ViewModels” folder to DemoShared (Portable) to hold this class:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Net;
using DemoShared.Models;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Newtonsoft.Json;

namespace DemoShared.ViewModels
{
  public class MainViewModel : ViewModelBase
  {
    public MainViewModel()
    {
      Photos = new ObservableCollection<Photo>();
    }

    public string DataUrl
    {
      get { return "http://169.254.80.80:28552/api/Photos"; }
    }

    public ObservableCollection<Photo> Photos { get; set; }

    private RelayCommand loadCommand;

    public RelayCommand LoadCommand
    {
      get
      {
        return loadCommand ?? (loadCommand = new RelayCommand(
            () =>
            {
              var httpReq = (HttpWebRequest)WebRequest.Create(new Uri(DataUrl));
              httpReq.BeginGetResponse((ar) =>
              {
                var request = (HttpWebRequest)ar.AsyncState;
                using (var response = (HttpWebResponse)request.EndGetResponse(ar))
                {
                  if (response.StatusCode == HttpStatusCode.OK)
                  {
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                      string content = reader.ReadToEnd();
                      if (!string.IsNullOrWhiteSpace(content))
                      {
                        var result = JsonConvert.DeserializeObject<List<Photo>>(content);
                        foreach (var g in result)
                        {
                          Photos.Add(g);
                        }
                      }
                    }
                  }
                }
              }, httpReq);
            }));
      }
    }

    private static MainViewModel instance;
    public static MainViewModel Instance
    {
      get
      {
        CreateNew();
        return instance;
      }
      set { instance = value; }
    }

    public static MainViewModel CreateNew()
    {
      if (instance == null)
      {
        instance = new MainViewModel();
      }
      return instance;
    }
  }
}

A rather standard MVVMLight viewmodel I might say, with the usual singleton pattern I use (I am not a big fan of "Locators"). When the command is fired, data is loaded from the WebApi url, deserialized to the same model code as was used to create it on the server, and loaded into the ObservableCollection. Nothing much special here.

There's one fishy detail - in stead of a computer name or “localhost”, there is this hard coded IP adress. We will get to that later.

Adding the Forms XAML page

Add a new Forms XAML page like this

image

Be aware that you have to enter the name manually, that’s a bug in the Xamarin tools, like Laurent Bugnion already described in his tutorial

Now, go to the DemoPage.Xaml.cs and set up the data context by adding one line of code to the constructor of the page:

public DemoPage()
{
  InitializeComponent();
  BindingContext = MainViewModel.Instance;
}

This will of course require a “using DemoShared.ViewModels;” at the top. Then we add our “XAML” to start page

<?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="DemoShared.DemoPage">
  <StackLayout Orientation="Vertical" Spacing="0">
    <Button Text="Click here" Command="{Binding LoadCommand}" 
            VerticalOptions="Start" HorizontalOptions="Center"  />
    <ListView ItemsSource="{Binding Photos}"
           RowHeight="50">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <ViewCell.View>
              <StackLayout Padding="5, 5, 0, 5"
                           Orientation="Vertical"
                           Spacing="2">
                <Label Text="{Binding ID}" Font="Bold, Large" 
                       TextColor="Red"/>
              </StackLayout>
            </ViewCell.View>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </StackLayout>
</ContentPage>

Now this looks kind of familiar, but also kind of - not really. Binding looks kind of you would expect, some controls have weird options, as some... well, have you ever seen a ViewCell before? Working with this stuff really makes you appreciate things like IntelliSense and Blend, for you have none of the above. Good old handcrafted XML. But - it does carry the magic of Xamarin Forms.

Finally, we make our start page the start page of the app. Go to App.cs in DemoShared (Portable) and change the GetMainPage method to:

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

imageimageThen I set a multiple startup project, setting both the Windows Phone project as well as the backend project as startup.

And sure enough, there’s the Windows Phone startup screen with one button. And if I click it…

 

I get an error.

And now for the fishy detail

So your backend is a website - running under IISExpress. By default, that’s not accessible by anything else but localhost, and not by IP adress. What you have to do is explained mostly here. First, find your applicationhost.config. It’s usually in

  • C:\Users\%USERNAME%\Documents\IISExpress\config or
  • D:\Users\%USERNAME%\Documents\IISExpress\config

In my case it’s the second one. Now before you start messing around in it, you might want to make a backup. Then open the file, and search for the text "*:28552”. This should yield you the following line:

<binding protocol="http" bindingInformation="*:28552:localhost" />

Make a copy of this line, directly below it. Replace localhost by the IP adress you found earlier using "ping -t –4 <hostname>". Net result, in my case:

<binding protocol="http" bindingInformation="*:28552:localhost" />
<binding protocol="http" bindingInformation="*:28552:169.254.80.80" />

Then – very important – close Visual Studio and restart as Administrator. For then and only then IISExpress will be allowed to bind to something else than localhost. That crucial bit of information is unfortunately hard to find.

And then, sure enough:

imageimage

It runs on Windows Phone and Android. And I am sure, on Apple stuff too but lacking Apple hardware and developer account I could not test it.

BTW – and alternative to messing around with IIS Express settings is of course host the website in IIS. But that requires apparently the database being hosted in SQL*Server Express, so it can’t be in App_Data like this. Or something like that. I found this made a quick test easier.

One more thing

If you want to test this from outside your computer, on a phone, you might want to open the port for TCP traffic:

image

Conclusion

Using Xamarin allowed us to shared code over multiple platform, but the Shared Reference Project Manager we could also share with the server. And the ease with which you can get a database powered backend up and running using EF code first was also quite impressive to me. Now tiny details, like security and upgrades, I leave as exercise to the reader.

Code can be found here.

28 July 2014

AngularJS + TypeScript – how to setup a watch (and 2 ways to do it wrong)

Introduction

After setting up my initial application as described in my previous post, I went about to set up a watch. For those who don’t know what that is – it’s basically a function that gets triggered when a scope object or part of that changes. I have found 3 ways to set it up, and only one seems to be (completely) right.

In JavaScript, you would set up a watch like this sample I nicked from Stack Overflow:

function MyController($scope) {
   $scope.myVar = 1;

   $scope.$watch('myVar', function() {
       alert('hey, myVar has changed!');
   });
   $scope.buttonClicked = function() {
      $scope.myVar = 2; // This will trigger $watch expression to kick in
   };
}

So how would you go about in TypeScript? Turns out there are a couple of ways that compile but don’t work, partially work, or have unexpected side effects.

For my demonstration, I am going to use the DemoController that I made in my previous post.

Incorrect method #1 – 1:1 translation.

/// <reference path="../scope/idemoscope.ts" />
/// <reference path="../scope/person.ts" />
module App.Controllers {
    "use strict";
    export class DemoController {

        static $inject = ["$scope"];

        constructor(private $scope: Scope.IDemoScope) {
            if (this.$scope.person === null || this.$scope.person === undefined) {
                this.$scope.person = new Scope.Person();
            }
            this.$scope.$watch(this.$scope.person.firstName, () => {
                alert("person.firstName changed to " +
                    this.$scope.person.firstName);
            });
        }

        public clear(): void {
            this.$scope.person.firstName = "";
            this.$scope.person.lastName = "";
        }
    }
} 

The new part is in red. Very cool – we even use the inline ‘delegate-like’ notation do define the handler inline. This seems plausible, but does not work. What it does is, on startup, give the message “person.firstName changed to undefined” and then it never, ever does anything again. I have spent quite some time looking at this. Don’t do the same – read on.

Incorrect method #2 – not catching the first call

To fix the problem above, you need to use the delegate notation at the start as well:

this.$scope.$watch(() => this.$scope.person.firstName, () => {
    alert("person.firstName changed to " +
        this.$scope.person.firstName);
});

See the difference? As you now type a “J” in the top text box, you immediately get a “person.firstName changed to J” alert. Making it almost impossible to type. But you get the drift.

But then we arrive at the next problem – this is still not correct: it goes off initially, when nothing has changed yet. This is undesirable in most occasions.

The correct way

It appears the callback actually has a few overloads with a couple of parameters, of which I usually only use oldValue and newValue to detect a real change. Kinda like you do in an INotifyPropertyChanged property:

this.$scope.$watch(() => this.$scope.person.firstName, 
                         (oldValue: string, newValue: string) => {
    if (oldValue !== newValue) {
        alert("person.firstName changed to " +
            this.$scope.person.firstName);
    }
});

Now it only goes off when there’s a real change in the watched property.

…and possibly an even better way

I am not really a fan of a lambda calling a lambda in a method call, so I would most probably refactor this to

constructor(private $scope: Scope.IDemoScope) {
    if (this.$scope.person === null || this.$scope.person === undefined) {
        this.$scope.person = new Scope.Person();
    }
    this.$scope.$watch(() => this.$scope.person.firstName, 
                            (oldValue: string, newValue: string) => {
        this.tellmeItChanged(oldValue, newValue);
    });
}

private tellmeItChanged(oldValue: string, newValue: string) {
    if (oldValue !== newValue) {
        alert("person.firstName changed to " +
            this.$scope.person.firstName);
    }
}

as I think this is just a bit more readable, especially if you are going to do more complex things in the callback.

Demo solution can be found here

27 July 2014

Angularjs + TypeScript – setting up a basic application with Visual Studio 2013

Preface

No, I have not abandoned Windows (Phone) Development, and am not planning to do that. But apart from being Windows Platform MVP (as it is called since a few weeks) I actually have a day job as an employee building web applications. A few years ago I brought in the SPA concept in the company, first based on Knockout, later Angular, and after the 2014 Dutch TechDays and actually having dinner with Erich Gamma I decided it was time to take on TypeScript. And the overall team lead agreed. Provided I would give some good feedback on my experiences. Well, how about this? ;)

Although I have ascertained the combination actually works very well, I really found myself in unchartered territory and it took some time to get off the ground. I started my blog in 2007 because there were not enough complete samples in the .NET world – well, in the web world this apparently goes squared and with a few VERY notable exceptions people are quite terse when it comes to giving help. I even got told off on Stack Overflow for commenting on an answer containing typos and suggested some calls were synchronous while in fact they were not. This is a apparently a whole different world than the helpful #wpdev community. Still, I soldiered on, and decided to do this blog post – or actually series of blog posts, that’s forged from the same fire as this blog itself: of frustration about lack of helpful samples.

I am not saying this the definitive guide to AngularJS and TypeScript – but it’s how I got stuff working, how I got to understand it, or at least I think I understand it. I hereby invite anyone thinking I do things wrong to provide corrections, or write better blog posts with better samples themselves. I will gladly link to you for credits.:)

I am not going to have a discussion about why to use TypeScript. I am going to assume you want to use it, that you know that in order to use it you will need files that type JavaScript types, and that you know the basics of creating a module, class or interface. This is mostly a how-to, with some explanations on the side. This article learns you:

  • The initial setup of the solution
  • What initial NuGet packages to get
  • How to create the base application
  • How to set up your first scope, view, controller and route

Prerequisites

I used

The last one is optional, but recommended. It gives a few extra options, as generating JavaScript classes from C# and (when you are typing TypeScript) seeing your code converted to JavaScript on the fly.

imageCreating a new project

  • File/New Project/Web/ASP.Net Web application (it’s the only choice you have)
  • Choose a name (I chose AtsDemo) and hit OK
  • Choose “Web Api” and UNSELECT “Host is the cloud”
  • Go to the NuGet Package manager and update all the packages, because a lot of them will be horribly outdated. Hit “accept” or “yes” on any questions
  • Delete the “Areas” and “Fonts” folder cause we won’t need them

Getting the additional NuGet packages

This is quite a list. Maybe it is too much for just a basic start, but I decided to load it all.

  • Angularjs
  • Angularjs.Animate
  • AngularJS.Cookies
  • AngularJS.Route
  • AngularJS.Sanatize
  • Angularjs.TypeScript.DefinitelyTyped
  • Jquery.TypeScript.DefinitelyTyped

Note that this will also pull in Angularjs.Core.

The TypeScript.DefinitelyTyped--files are definitions that make it possible to use typed versions of Angular and Jquery from TypeScript.

Set up the initial application

  • Add a folder “app” to the root folder of your web project
  • Add a file AppBuilder.ts to the app folder with the following contents:
module App {
    "use strict";
    export class AppBuilder {


        app: ng.IModule;

        constructor(name: string) {
            this.app = angular.module(name, [
            // Angular modules 
                "ngAnimate",
                "ngRoute",
                "ngSanitize",
                "ngResource"
            ]);
        }

        public start() {
            $(document).ready(() =>
            {
                console.log("booting " + this.app.name);
                angular.bootstrap(document, [this.app.name]);
            });
        }
    }
}

This is the basic setup for a class I use to ‘construct’ my app. I don’t like to do this in the global namespace. So I create a basic ‘module’ – which I tend to think of as a .NET namespace – in the “AppBuilder” in the namespace “App”.

Then add another file to app, called “start.ts”, to create an AppBuilder instance and call “start” to bootstrap your Angular app:

/// <reference path="appbuilder.ts" />
new App.AppBuilder('atsDemo').start();

By the way, the first line indicates this uses a type defined in appbuilder.ts. It’s good practice to add these references, although mostly (but certainly not always) the compiler seems to find the references itself. You can make these references easily by dropping one file on top of the other form the solution explorer (so in this case, I dropped AppBuilder.ts on top of start.js).

Then

  • right-click your web project,
  • select properties,
  • go to the “TypeScript Build” tab,
  • select “combine Javascript into output file”
  • Enter “app/app.js” in the text box

Net result: see below.

image

Build your project, and verify that in the app folder the files “app.js” and “app.js.map” appear. Don’t include them in your project – when working with TypeScript it’s best to think of the created JavaScript as binaries. I use this options mainly to prevent loading order issues with regards to the resulting JavaScript, but it also makes the loading of JavaScript faster – now there’s only one file to load, in stead of more – and when you use TypeScript, it becomes quite a lot of files soon. Of course, you might also go for something like AMD with requirejs but for the somewhat smaller sites I tend to write, this works pretty well.

Then, open App_Start/Bundleconfig.cs and add the following lines just before the comment line "//Set EnableOptimizations to false for debugging. For more information,"

bundles.Add(new ScriptBundle("~/bundles/angular").Include(
    "~/Scripts/angular.js",
    "~/Scripts/angular-animate.js",
    "~/Scripts/angular-cookies.js",
    "~/Scripts/angular-route.js",
    "~/Scripts/angular-sanitize.js",
    "~/Scripts/angular-resource.js"
    ));

bundles.Add(new ScriptBundle("~/bundles/app").Include(
"~/app/app.js"));

This will include Angular files, as well as the JavaScript generated from the TypeScript. Finally, the last code line says

BundleTable.EnableOptimizations = true;

Change "true" to “false”. Then go to the Views/Shared/_Layout.cshtml. Change it’s contents to this:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>@ViewBag.Title</title>
  @Styles.Render("~/Content/css")
  @Scripts.Render("~/bundles/modernizr")
</head>
<body>
  <div class="container body-content">
    @RenderBody()
  </div>
  @Scripts.Render("~/bundles/jquery", "~/bundles/angular", "~/bundles/app")
  @RenderSection("scripts", required: false)
</body>
</html>

This will load the all the necessary scripts. Finally visit the Views/Home/Index.cshtml file. Delete it’s contents and replace it by just this:

@{
  ViewBag.Title = "Home Page";
}
 angulartest={{1+1}}
<div data-ng-view=""></div>

The “angulartest={{1+1}}“ line is just to see if Angular works. The div below it is the place where we will inject our views (see later).

Test the setup

Run the application from Visual Studio in your browser of choice. Hit F12 as soon as the browser starts. In your console it should say “booting atsDemo”, an in your browser window it should say “angulartest=2”

image

If you see this, then a) Angular is correctly loaded and activated (or else your browser window most likely displays “angulartest={{1+1}}”, meaning the expression is not evaluated and replaced and b) your application written in TypeScript actually has booted. Now it does nothing yet, but that’s the next step. For people who want to reference this stage, you can download the solution for this stage here. It may be useful if you just want a starter point.

Defining a scope object and a scope

The thing about TypeScript is typing, and you can also type your scope. Now the same caveats apply as to ‘normal’ Angular – if you go into a child scope or sub scope, or whatever they may be called, you can access but not change the parent scope – unless you specifically access it. That is quite of a hassle,  so it’s good practice to create an object to put on the scope, and manipulate that object – and not the scope itself. That’s basically Angular, and has nothing to do with TypeScript per se.

So I first added a folder “scope” to my app folder, and created the following object to hold person data:

module App.Scope {
    "use strict";
    export class Person {
        public firstName: string
        public lastName: string
    }
}
And then, to use it in the scope, I define and interface telling TypeScript that my scope, apart from the usual things that Angular provides, should at least contain a person of type Person:
/// <reference path="person.ts" />
module App.Scope {
    "use strict";
    export interface IDemoScope extends ng.IScope {
        person : Person
    }
}

Important to remember is that an interface is purely aTypeScript construct. It does not exist in JavaScript. If you look into the resulting app.js file, you won't find an IDemoScope. You won't find any interface. It's just a scaffold to help you not make typos in addressing this particular scope again. It needs to extend ng.IScope, a predefined interface from the DefinitelyTyped file.

Defining a controller

Add a folder “controller” to your app folder, and add a simple controller that allows you to enter the fields but also clear them again. 

/// <reference path="../scope/idemoscope.ts" />
/// <reference path="../scope/person.ts" />
module App.Controllers {
    "use strict";
    export class DemoController {
        static $inject = ["$scope"];

        constructor(private $scope: Scope.IDemoScope) {
            if (this.$scope.person === null || this.$scope.person === undefined) {
                this.$scope.person = new Scope.Person();
            }
        }
        public clear(): void {
            this.$scope.person.firstName = "";
            this.$scope.person.lastName = "";
        }
    }
}

As you can see, a controller is just a plain old class not extending anything special, with a pubic method to clear the fields of a person. It has a few things to note.

  • It’s the first class I show with an actual constructor. In that constructor it makes sure the person in the scope is initialized if necessary.
  • Note that putting “private” in front of a constructor parameter automatically creates a private class member which can be henceforth referenced by this.$scope
  • There is a static $inject variable. Although you are supposed to create the controller in the AppBuilder (see later) and only then inject the scope into in, apparently to prevent minification issues you have to provide this array too.

Defining a view

Create a folder “views” in you “app” folder, then add a file “PersonView.html” with the following very complex HTML in it:

<div>
  <div>
    <input type="text" data-ng-model="person.firstName" />
  </div>
  <div>
    <input type="text" data-ng-model="person.lastName" />
  </div>
  <div>{{person.firstName}}</div>
  <div>{{person.lastName}}</div>
  <button data-ngclick="myController.clear()">Clear</button>
</div>
This will give you a text box to enter the fields in, some feedback text below it to show data binding actually works, and a button to clear the fields again to see we can also actually can call bind to the controller - in this case a method.

Defining the controller in the AppBuilder

Just before the closing accolade } of the constructor, add this code:
this.app.controller("personController", [
    "$scope", ($scope)
        => new App.Controllers.DemoController($scope)
]);
or  if you want to super safe, explicitly type the scope explicitly so the controller get's the exact type of scope it expects.
this.app.controller("personController", [
    "$scope", ($scope : Scope.IDemoScope)
        => new App.Controllers.DemoController($scope)
]);

I find two things odd about this:

  • The fact that the first code works as well, while I would expect it would not – anything that is not typed explicitly is type “any” but clearly that does not fit into the constructor
  • This compiles without making a reference to the files containing IDemoScope and DemoController.

Anyway, for good measure I always add these references just to make sure. I have been running into some odd problems where references suddenly could not be found anymore.

Creating the route definition

Once again, just before the last accolade of the AppBuilder constructor, add this code:

this.app.config([
    "$routeProvider",
    ($routeProvider: ng.route.IRouteProvider) => { 
        $routeProvider
            .when("/person",
            {
                controller: "personController",
                controllerAs: "myController",
                templateUrl: "app/views/personView.html"
            })
            .otherwise({
                redirectTo: "/person"
            });
    }
]);
This defines a single route "person", which is also the default route, for which it will use the personController, the view personView.html, and what is very important and had me searching for quite some time - it defines a binding alias for the controller in the router, in code. Almost all the samples I found where controller definitions in html, e.g.
<div data-ng-controller="personController as myController">
...
</div>
but it took me quite some time to find out how to do it from code. Which I had to be able  to do, as I sometimes have use a different controller on the same view. Well, this is how you do that: use "controllerAs" in your router definition.

Kick start the router

Finally, to get the router working and started, add once again a piece of code just before the last accolade of the AppBuilder constructor :

this.app.run([
    "$route", $route => {
        // Include $route to kick start the router.
    }
]);

And we’re done… for now

imageIf you run the code, you should see the url in the browser go from http://localhost:3987/ to http://localhost:3987/#/person, indicating your router is now in control, and it should show the beautiful *cough* UI on the right. I typed “Joost” in the first box and “van Schaik” in the second and as you type, the line below it should change with it, indicating data binding works to the scope. And the “Clear” clears both the boxes and the display lines, showing binding to the controller works as well.

Conclusion

Setting up an Angular + TypeScript application in Visual Studio 2013 is not that hard to do, once you know how to do it. I hope this post will save other developers from the stumbling around I did. I am, by far, not finished, but what I now have are more small gotcha’s, things you need to know and things that are apparently common knowledge, self-explanatory, blindingly obviously or buried deep inside documentation everyone seems to know by heart as no-one explains or mentions them to mere mortal (web) developers such as myself ;) 

The full solution, as always, can be downloaded here, so you can see for yourself how things work in it’s totality, in stead of having to hunt it down piecemal from Stack Overflow.

Thanks

Special thanks to a few of the “notable exceptions” who helped me along the way to get here (and further)

16 July 2014

Cross-platform behavior for making screenshots in Windows (Phone) 8.1

Currently I am developing an app that should be able to share or save whatever is on the screen. I came upon this article by Loek van den Ouweland about RenderTargetBitmap and wondered if I could a) make this more generally (re)usable and b) make it play nice with MVVM.

The answer was – you guessed it – a behavior. The fun thing is, you can drag it onto any UI element, and it will create a screenshot of whatever what’s inside that element ( and that’s not necessary the whole screen!) and save it to storage. Two dependency properties, Target and Prefix, determine what message the behavior listens to, and what the file prefix is.

The main code of the functionality – which still looks a lot like Loek’s original sample – is in the behavior itself. To invoke it from the viewmodel, I call in the help of the MVVMLight messenger. So I start with the message that the viewmodel and the behavior use to communicate:

using GalaSoft.MvvmLight.Messaging;

namespace WpWinNl.Behaviors
{
  public class ScreenshotMessage : MessageBase
  {
    public ScreenshotMessage(object sender = null, object target = null, 
      ScreenshotCallback callback = null) : base(sender, target)
    {
      Callback = callback;
    }

    public ScreenshotCallback Callback { get; set; }
  }

  public delegate void ScreenshotCallback(string fileName);
}

This is a standard MVVMLight message, with the added extra that it can carry an optional payload of a callback. The behavior I created saves the file to a KnownFolder, but it can send the name of the file that’s been created back to the calling object by calling said callback.

The basics of the behavior – implemented once again as a SafeBehavior – is actually pretty simple:

using System;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
using GalaSoft.MvvmLight.Messaging;

namespace WpWinNl.Behaviors
{
  public class ScreenshotBehavior : SafeBehavior<FrameworkElement>
  {
    protected override void OnSetup()
    {
      Messenger.Default.Register<ScreenshotMessage>(this, ProcessMessage );
      base.OnSetup();
    }

    protected override void OnCleanup()
    {
      Messenger.Default.Unregister(this);
      base.OnCleanup();
    }

    private async void ProcessMessage(ScreenshotMessage m)
    {
      if (m.Target != null && Target != null)
      {
        if (m.Target.Equals(Target))
        {
          await DoRender(m.Callback);
        }
      }
      else
      {
        await DoRender(m.Callback);       
      }
    }
  }
}

So it listens to a ScreenshotMessage coming by. When Target (a dependency property in this behavior) is equal to the target specified in the message, the rendering is done. Think of Target as a shared key – this enables a viewmodel to fire a specific behavior using – usually - a string. This I show in the sample solution. If both the behavior’s target and the message’s target are null, it fires as well. You can use this if you only have one behavior and one call. If, however, the behavior is used on multiple places I strongly recommend specifying Target, or else you might get very interesting race conditions.

The actual rendering method is nearly all Loek’s code with some little adaptions:

private async Task DoRender(ScreenshotCallback callback)
{
  var renderTargetBitmap = new RenderTargetBitmap();
  await renderTargetBitmap.RenderAsync(AssociatedObject);
  var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();

  var storageFile = 
    await KnownFolders.SavedPictures.CreateFileAsync(
      string.Concat(Prefix, ".png"),
      CreationCollisionOption.GenerateUniqueName);
  using (var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
  {
    var encoder = 
await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream); encoder.SetPixelData( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint) renderTargetBitmap.PixelWidth, (uint) renderTargetBitmap.PixelHeight, 96d, 96d, pixelBuffer.ToArray()); await encoder.FlushAsync(); if (callback != null) { callback(storageFile.Name); } } }

It creates an unique file based on the Prefix dependency property in the “SavedPictures” known folder, renders the screen as a png file, saves it, and if so desired calls a callback transmitting the name back to that callback – most likely a method of the viewmodel, which can then act on it.

The rest of the behavior are the two dependency properties that I leave out for brevity's sake.You don’t need to use them at all – if you don’t set Prefix, it will use “Screenshot”

To use it: as stated earlier, drag it on top of the UI element you want to make screenshots of, then add for instance the following code to your viewmodel:

public ICommand ScreenshotCommand
{
  get
  {
    return new RelayCommand(() =>
    {
      var m = new ScreenshotMessage(this, 
        "screenshot", MyCallback);
      Messenger.Default.Send((m));
    });
  }
}

private void MyCallback(string name)
{
  Debug.WriteLine(name);
}
In the message I have set the target to "screenshot", so in the XAML it should now says
<Behaviors:ScreenshotBehavior Target="screenshot" Prefix="MyScreenshot"/>

or else the behavior won’t respond to the message. When it’s done, it writes the name of the created file to the console – not very useful in production scenario’s, but it shows it’s working. In this callback you can for instance inform the user the file has been saved, activate a share contract or whatever you feel is neccesary.

The fun thing is, of course, that in this awesome world we live today behaviors can actually be cross-platform and be defined in a PCL and run both on Windows Phone 8.1 as on “big Windows” 8.1 :).

MyScreenshotMyScreenshot (2)

In the demo solution, that contains both a Windows Phone App, a Windows App, and a shared project you will see I have once again dragged the Main.Xaml to the shared project just for the fun of it. Don’t forget to set access to the pictures library in both the app manifests. I always forget that.

MyScreenshotFor Windows, the pictures end up in my “USERPROFILE%\Picures” folder, in Windows Phone they end up in “Pictures\Saved Pictures”.

Interesting detail – I have set the application’s root grid background to gray. If I don’t set a color, the background of the picture on Windows is not black, but cropped to 1297x1080 in stead of 1920x1080 as is my native resolution. I have not been able to determine yet why this is.

I built this behavior on top of my WpWinNl 2.0.3 package, but you can easily adapt it to get it to work as a normal behavior just using the procedure I described here.

Oh and the picture? It’s just an old picture of my wife’s Mercedes truck back in 2004, when she and a colleague joined a Guinness Book of records attempt to create the longest truck convoy ever. This is a short stop at dyke road shoulder before the actual 9.5 km long convoy was assembled. Interesting detail: all 416 drivers were women. The convoy drove 22 km without any problems, and as my wife so aptly said – it was the first time she joined a traffic jam for fun.

25 June 2014

Using SensorCore and MVVMLight to build a ‘what did I do where and when’ Windows Phone 8.1 app

Introduction

As you might have seen, the SensorCore SDK has been released. I intended to bring out a full fledged app utilizing this new and exiting SDK, but I found out that I first had to explain a bit about the ‘supporting acts’ I was going to use – if you study my last four posts you will see they all contain parts of the sample app that goes what this post. In addition, the last month I had a rather time- and energy-consuming, frustrating, ultimately fruitless and disappointing thing cross my way with which I won’t bother you with – sufficient to say I would rather have spent this time on writing apps.

Anyway. I set out to make an app that would use the both the SensorCore ActivityMonitor and TrackPointMonitor, as well as the existing MapLocationFinder to find out what I was doing where, and when.

For those who are not familiar with the concept of SensorCore: a few newer devices, among which the Lumia 630, have hardware aboard that allows you to track where the user has been about every 5 minutes, and what he was doing, for the last 10 days. Based upon this information, it designates places that are apparently important to the owner (like home, work). In addition, it has a step counter. Everything is handled by a special, very low power piece of hardware that continuously tracks location and movement with very little battery drain.

Now for the tin foil hat crew: there are some key differences to the way other platforms handle this. First of all, it can only happen with the user’s consent – it’s a phone setting that has to be explicitly turned on, and then and only then the hardware starts to collect data. Furthermore, this data never leaves the phone all by itself – there is no Bing server tracking your actions to clutter your phone with ads or other stuff you may not necessarily appreciate. The only way this data can ever leave your phone is by some for of app – but first you have to give the phone consent, then the app, and said app has to pass certification as well. This Windows/Windows Phone ecosystem takes your privacy very seriously. Ask any developer – almost everyone has been rejected at least once over some tiny detail they missed in the privacy sections of the certification requirements ;-)

The app I am going to show you looks like this. With sincere apologies for the video quality – apparently maps on a slow device is a bit too much for a cable connection with a Lumia 630, but it shows the gist.

SensorCore and MVVMLight

Setting the stage

So I created a Windows Phone 8.1 (Store) app WhatWhenWhere with one supporting class library WpWinNl.MvvmLight.Contrib. I added my WpWinNlMaps NuGet packages to both projects, and added PropertyChanged.Fody as well to it. The contrib package holds BaseNotifyingModel and TypedViewModelBase – as described in this article on using PropertyChanged.Fody for Model-to-Viewmodel communication

An other minor detail – you might want to pull in the Lumia SensorCore NuGet package as well ;-)

A model to hold one location

So I needed a model to know where and when something happened (a TrackPointMonitor TrackPoint), what I was doing there (an ActivityMonitorReading) and an approximate street address (a MapLocationFinder MapLocation). First analysis learns that an ActivityMonitorReading only holds a Timestamp and an Activity. This activity describes what I was doing (Idle, Moving, Stationary, Walking or Running). As I already know the time from the TrackPoint, and I only use that Timestamp to get the accompanying Activity, we might as just only hold that Activity, and not the whole ActivityMonitorReading.

So I created the following model class:

using System;
using System.Linq;
using Windows.Devices.Geolocation;
using Windows.Services.Maps;
using Lumia.Sense;
using WpWinNl.MvvmLight;

namespace WhatWhenWhere.Models
{
  public class ActivityPoint : BaseNotifyingModel
  {
    public ActivityPoint()
    {
    }

    public ActivityPoint(TrackPoint p)
    {
      LengthOfStay = p.LengthOfStay;
      Position = p.Position;
      Radius = p.Radius;
      Timestamp = p.Timestamp;
    }

    public ActivityPoint(TimeSpan lengthOfStay, BasicGeoposition position, 
      double radius, DateTimeOffset timestamp, Activity activity)
    {
      LengthOfStay = lengthOfStay;
      Position = position;
      Radius = radius;
      Timestamp = timestamp;
      Activity = activity;
    }

    public TimeSpan LengthOfStay { get; set; }
    public BasicGeoposition Position { get; set; }
    public double Radius { get; set; }
    public DateTimeOffset Timestamp { get; set; }
    public Activity Activity { get; set; }

    public MapLocation LocationData { get; set; }

    public void LoadAddress()
    {
      if (LocationData == null)
      {
        MapLocationFinder.FindLocationsAtAsync(
new Geopoint(Position)).AsTask().ContinueWith(p => { var firstLocationData = p.Result.Locations; if (firstLocationData != null) { LocationData = firstLocationData.FirstOrDefault(); } }); } } } }

Which has, unlike the TrackPoint and the ActivityMonitorReading, the added benefit of being serializable on account of having a default constructor (ahem) which comes in handy when doing storing state when the app is deactivated (note: the demo app does not handle that).

You might notice the LoadAddress method that can called externally to load the address on demand (in stead of just doing that in the constructor. This has been done for performance reasons – geocoding and loading addresses is expensive and  slow, and you don’t want to do that if you are not sure if the user actually wants to see those addresses or not. So you defer that to the last possible moment – when the user actually selects this object.This technique is described in detail in this article .Notice it carefully avoids the way how you obtain these locations ;-) .

A model to load the data.

The bulk of the DataLoaderModel is shamelessly stolen from the samples.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using GalaSoft.MvvmLight.Messaging;
using Lumia.Sense;
using WhatWhenWhere.Models.Messages;
using Tracker = Lumia.Sense.TrackPointMonitor;

namespace WhatWhenWhere.Models
{
  public class DataLoaderModel
  {
    public DataLoaderModel()
    {
    }

    public async Task Init()
    {
      await InitTracker();
      await InitActivityMonitor();
    }

    private Tracker tracker;
    private async Task<bool> InitTracker()
    {
      if (await Tracker.IsSupportedAsync())
      {
        if (tracker == null)
        {
          if (await CallSensorcoreApiAsync(async () =>
              tracker = await Tracker.GetDefaultAsync()))
          {
            return true;
          }
        }
      }
      return false;
    }

    private ActivityMonitor activityMonitor;

    private async Task<bool> InitActivityMonitor()
    {
      if (await ActivityMonitor.IsSupportedAsync())
      {
        if (activityMonitor == null)
        {
          if (await CallSensorcoreApiAsync(async () =>
              activityMonitor = await ActivityMonitor.GetDefaultAsync()))
          {
            return true;
          }
        }
      }
      return false;
    }

    public async Task SetSensorState(bool enable)
    {
      await SetSensorState(tracker, enable);
      await SetSensorState(activityMonitor, enable);
    }

    private async Task SetSensorState(ISensor sensor, bool active)
    {
      if (sensor != null)
      {
        if (!active)
        {
          await CallSensorcoreApiAsync(async () => 
{ await sensor.DeactivateAsync(); }); } else { await CallSensorcoreApiAsync(async () =>
{ await sensor.ActivateAsync(); }); } } } private async Task<bool> CallSensorcoreApiAsync(Func<Task> action) { try { await action(); } catch (Exception ex) { SenseHelper.GetSenseError(ex.HResult); Messenger.Default.Send( new SenseFailureMessage(SenseHelper.GetSenseError(ex.HResult), this)); // This is now not handled, but should really be handled as described here // (Calling the SensorCore SDK safely) return false; } return true; } } }

It has some clever tricks with Lambdas to be able to call SensorCore methods without having to copy & past the whole try/catch stuff. I basically only added in both sensors, and let it send out an error message via the MVVMLight Messenger if things go wrong (note: app does not handle this, but I think it’s a good pattern).

I did add some code to this stolen-from-sample class, to actually load the data into the model:

public public async Task<bool> LoadInitialData()
{
  if (tracker != null && activityMonitor != null)
  {
    var result = await tracker.GetTrackPointsAsync(
       DateTime.Now - TimeSpan.FromDays(10), TimeSpan.FromDays(10));
    if (RoutePoints == null)
    {
      RoutePoints = new List<ActivityPoint>(result.Select(p => new ActivityPoint(p)));
    }
    else
    {
      RoutePoints.Clear();
    }
    await LoadActivities();
    return true;
  }
  return false;
}

private async Task LoadActivities()
{
  foreach (var r in RoutePoints)
  {
    try
    {
      var reading = await activityMonitor.GetActivityAtAsync(r.Timestamp);
      r.Activity = reading.Mode;
    }
    catch (Exception ex)
    {  // lame – I know.
    }
  }
}

public List<ActivityPoint> RoutePoints { get; set; }

This is the core of the whole app – the rest is fluff to make things visible. LoadInitialData first loads all the TrackPoints from the last 10 days (which is the maximal available time anyway) and converts them into my ActivityPoint model. It then proceeds to find the actual activity that was performed at the time the TrackPoint was recorded. And if you call the ActivityPoint’s LoadAddress method, it will find the (approximate) address of the location it was recorded – it will even return highway names (it’s won’t find a house number then, but I don’t think that will surprise anyone).

A view model for a single point

Quite a lot of how this this works, is already described in my article on using PropertyChanged.Fody. I can directly bind to the model, but for formatting output and commands I like to keep my model clean and employ a viewmodel for that.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Input;
using Windows.Devices.Geolocation;
using Windows.Services.Maps;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using WhatWhenWhereMessages;
using WhatWhenWhere.Models;
using WpWinNl.MvvmLight;

namespace WhatWhenWhere.ViewModels
{
  public class ActivityViewModel : TypedViewModelBase<ActivityPoint>
  {
    public ActivityViewModel()
    {
    }

    public ActivityViewModel(ActivityPoint p) : base (p)
    {
    }
  
    public Geopath Location
    {
      get
      {
        return new Geopath(new[] { Model.Position });
      }
      set
      {
        var p = value.Positions.FirstOrDefault();
        if (Model.Position.Equals(p))
        {
          Model.Position = p;
          RaisePropertyChanged(() => Location);
        }
      }
    }

    public string DateAndTime
    {
      get
      {
        return Model != null ? 
Model.Timestamp.ToString("dd-MM-yyyy hh:mm:ss",
CultureInfo.InvariantCulture) : string.Empty; } } public string LocationName { get { return Model != null && Model.LocationData != null ?
GetFormattedAdress(Model.LocationData.Address) : string.Empty; } } private string GetFormattedAdress(MapAddress a) { if (a == null) throw new ArgumentNullException("a"); return string.Format("{0} {1} {2} {3}",
a.Street, a.StreetNumber, a.Town, a.Country); } public ICommand SelectCommand { get { return new RelayCommand( () => { Messenger.Default.Send(new SelectedObjectMessage(this)); Model.LoadAddress(); }); } } public ICommand DeSelectCommand { get { return new RelayCommand( () => Messenger.Default.Send(new SelectedObjectMessage(null))); } } protected override void ModelPropertyChanged(object sender,
PropertyChangedEventArgs e) { if (e.PropertyName == "LocationData") { DispatcherHelper.CheckBeginInvokeOnUI(() =>
RaisePropertyChanged(() => LocationName)); } } } }

There are a few things that might attract your attention:

  • The Location in this viewmodel is a GeoPath of only one position. This is because I want to re-use my MapBinding assembly that I originally created for Windows Phone 8, and recently ported to Windows Phone 8.1
  • The SelectCommand explicitly launches the loading of the address when the viewmodel is selected. In my previous sample I showed a way to do this in the getter of a property, but this is a better way I think (as I already said then)
  • The ModelPropertyChanged method launches a RaisePropertyChanged using MVVMLight’s DispatcherHelper. While this is very useful, it requires the DispatcherHelper to be initialized in the App.Xaml.cs. We will get to that later.

Bringing it all together

The MainViewModel is always my ‘class that brings it all together’. I won’t show all details here, or this article will be even longer than it already is. I start with some initialization stuff:

using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.Devices.Geolocation;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using WhatWhenWhereMessages;
using WhatWhenWhere.Models;
using WpWinNl.Messages;
using WpWinNl.Utilities;

namespace WhatWhenWhere.ViewModels
{
  public class MainViewModel : ViewModelBase
  {
    public async Task Start()
    {
      if (Activities == null)
      {
        Activities = new ObservableCollection<ActivityViewModel>();
      }

      if (Route == null)
      {
        Route = new ObservableCollection<RouteViewModel>();
      }

      Messenger.Default.Register<WindowVisibilityMessage>(this, async m =>
      {
        await ProcessWindowVisibilityMessage(m);
      });

      Messenger.Default.Register<SelectedObjectMessage>(this, 
ProcessSelectedObjectMessage); await Model.Init(); } private void ProcessSelectedObjectMessage(SelectedObjectMessage message) { SelectedItem = message.Activity; } private async Task ProcessWindowVisibilityMessage(WindowVisibilityMessage m) { if (Model != null) { if (!IsInDesignMode) { await Model.SetSensorState(m.Visible); } } } } }

And you can also see the viewmodel listens to two messages: one that is fired when an object is selected, and one that is fired when the main windows becomes visible (or invisible) - and sets the sensor state according to that. The second half of the MainViewModel mostly contains data properties and a command:

public ICommand LoadCommand
{
  get
  {
    return new RelayCommand(
      async () =>
      {
        await Model.LoadInitialData();
        Model.RoutePoints.ForEach(p => Activities.Add(new ActivityViewModel(p)));
        Route.Clear();
        var route = new RouteViewModel(Activities);
        Route.Add(route);
        ViewArea = GeoboundingBox.TryCompute(route.Path.Positions);
      });
  }
}

public ObservableCollection<RouteViewModel> Route { get; set; }

public ObservableCollection<ActivityViewModel> Activities { get; set; }

private GeoboundingBox viewArea = GeoboundingBox.TryCompute(new[] 
  { new BasicGeoposition { Latitude = -90, Longitude = -90 }, 
    new BasicGeoposition { Latitude = 90, Longitude = 90 } });

public GeoboundingBox ViewArea
{
  get { return viewArea; }
  set
  {
    if (viewArea != value)
    {
      viewArea = value;
      RaisePropertyChanged(() => ViewArea);
    }
  }
}

private ActivityViewModel selectedItem;
public ActivityViewModel SelectedItem
{
  get { return selectedItem; }
  set
  {
    if (selectedItem != value)
    {
      selectedItem = value;
      RaisePropertyChanged(() => SelectedItem);
    }
  }
}

Notice the LoadCommand: not only it loads the activities into a view model, but it also makes a new RouteViewModel (for drawing one line between all the points) and a bounding box to make all the points fit into the view. The RouteViewModel itself is a very simple thing that creates a GeoPath from all the points of all activities:

using System.Collections.Generic;
using System.Linq;
using Windows.Devices.Geolocation;
using GalaSoft.MvvmLight;

namespace WhatWhenWhere.ViewModels
{
  public class RouteViewModel : ViewModelBase
  {
    public RouteViewModel()
    {
    }

    public RouteViewModel(IEnumerable activities)
    {
      Path = new Geopath(activities.Select(p => p.Location.Positions.First()));

    }

    private Geopath geoPath;
    public Geopath Path
    {
      get { return geoPath; }
      set
      {
        if (geoPath != value)
        {
          geoPath = value;
          RaisePropertyChanged(() => Path);
        }
      }
    }
  }
}

And a wee bit of XAML to glue it all together

Being a lazy ****** and not wanting to think of something to draw all the stuff on a map, I reused both my Map Drawing behavior as the trick to show a popup, and came out with pretty little XAML indeed:

<Page.BottomAppBar>
  <CommandBar>
    <AppBarButton Icon="Accept" Label="Load" Command="{Binding LoadCommand, Mode=OneWay}"/>
  </CommandBar>
</Page.BottomAppBar>

<!-- stuff snipped -->

<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">
  <interactivity:Interaction.Behaviors>
    <behaviors:SizeListenerBehavior x:Name="ContentRootListener"/>
  </interactivity:Interaction.Behaviors>
  <Button Content="Button" HorizontalAlignment="Left" Margin="246,208,0,0" 
        VerticalAlignment="Top" Command="{Binding LoadCommand}"/>

  <Maps:MapControl maps:MapBindingHelpers.MapViewArea="{Binding ViewArea}">
    <interactivity:Interaction.Behaviors>
      <maps:MapShapeDrawBehavior LayerName="Locations" 
        ItemsSource="{Binding Activities}" 
        PathPropertyName="Location">
        <maps:MapShapeDrawBehavior.EventToCommandMappers>
          <maps:EventToCommandMapper EventName="MapTapped" 
            CommandName="SelectCommand"/>
        </maps:MapShapeDrawBehavior.EventToCommandMappers>
        <maps:MapShapeDrawBehavior.ShapeDrawer>
          <maps1:MapActivityDrawer/>
        </maps:MapShapeDrawBehavior.ShapeDrawer>
      </maps:MapShapeDrawBehavior>
        
      <maps:MapShapeDrawBehavior LayerName="Route" 
        ItemsSource="{Binding Route}" 
        PathPropertyName="Path">
        <maps:MapShapeDrawBehavior.ShapeDrawer>
          <maps:MapPolylineDrawer Color="Green" Width="3" 
                     StrokeDashed="True"/>
        </maps:MapShapeDrawBehavior.ShapeDrawer>
      </maps:MapShapeDrawBehavior>    
     </interactivity:Interaction.Behaviors>
  </Maps:MapControl>
    <Grid DataContext="{Binding SelectedItem}" 
        Height="{Binding WatchedObjectHeight, ElementName=ContentRootListener, 
           Converter={StaticResource PercentageConverter}, ConverterParameter=30}" 
           VerticalAlignment="Bottom" Background="Black" >
      <interactivity:Interaction.Behaviors>
        <behaviors:UnfoldBehavior RenderTransformY="1"  Direction="Vertical"  
        Activated="{Binding Converter={StaticResource NullToBooleanConverter}}"/>
      </interactivity:Interaction.Behaviors>
      <userControls:RouteItemPopup >
    </userControls:RouteItemPopup>
    </Grid>
  </Grid>
</Grid>

If you want more info on how these behaviors for binding elements to a MapControl work, I suggest you look at the original article explaining how they should be used. If a user taps on a map symbol, a popup with activity data is shown, and the address where that happened is loaded. Basically the same trick as I used here

Start it up

It’s important to initialize the Dispatcher helper, start new MainViewModel, and setup the WindowVisibilityMessage. I have talked about this before, but I thought it wise to repeat it one more time.

protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
    DispatcherHelper.Initialize();
    MainViewModel.CreateNew();
    await MainViewModel.Instance.Start();
    WindowVisibilityMessage.Setup();
// more
Notice the OnLaunched needs to be async, because of the async nature of the Start method.

…and a class to draw a different image for every activity

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Geolocation;
using Windows.Foundation;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Controls.Maps;
using Lumia.Sense;
using WhatWhenWhere.ViewModels;
using WpWinNl.Maps;

namespace WhatWhenWhere.Maps
{
  public class MapActivityDrawer : MapShapeDrawer
  {
    public override MapElement CreateShape(object viewModel, Geopath path)
    {
      var activityModel = ((ActivityViewModel) viewModel).Model;
      return new MapIcon
      {
        Location = new Geopoint(path.Positions.First()),
        Title = activityModel.Activity.ToString(),
        NormalizedAnchorPoint = new Point(0.5,1),
        Image = GetImage(activityModel.Activity)
      };
    }

    private static RandomAccessStreamReference GetImage(Activity activity)
    {
      var image = "Other";
      switch (activity)
      {
        case Activity.Idle:
        {
          image = "Idle";
          break;
        }
        case Activity.Walking:
        {
          image = "Walking";
          break;
        }

        case Activity.Moving:
        {
          image = "Moving";
          break;
        }

        case Activity.Stationary:
        {
          image = "Stationary";
          break;
        }
      }
      return RandomAccessStreamReference.CreateFromUri(
         new Uri(string.Concat("ms-appx:///Images/", image, ".png")));

    }
  }
}

Basically, translates every bound object back to ActivityViewModel, and draws a different image for it. This can be made more efficient, but this shows a way it could work.

Conclusion: the good and the bad parts

As you have seen, using SensorCore is actually pretty easy. Making it work together with MVVMLight as well, although I am very well aware that all the stuff I used around it may make it look a bit more convoluted that it actually is. The DataLoaderModel is all you have to understand. The rest is just the app around it.

The bad parts of SensorCore are pretty simple:

  • It’s still in beta
  • It requires a Windows Phone 8.1 phone with a Lumia Cyan update and the required hardware aboard. Currently, to the best of my knowledge, only the Lumia 630 has both the required hardware and software, although I assume the 930 will have it too.
  • The TrackPointMonitor only gives a position every 5 minutes – at the very best. Sometimes it misses points. So forget about a super-duper-detailed tracking of your location.

Another bad part – but that is more my bad – is that I have not included a way to run this on simulated data. A NuGet package allows you to test against fake or prerecorded data, so you can try your app without having access to an actual device have the sensors on board. I made this using a real live 630. To get this to work properly, you will need one too. The good part is: they are dirt cheap.

The good parts are a lot better:

  • Very simple and easy-to-use API.
  • Possibility to do geographical tracking and analysis after-the-fact
  • All kinds of fun apps possible, like fitness apps, life logging, and stuff like that
  • Very low power consumption (unlike ‘active’ GPS enabled apps)
  • Privacy is secured – no big brother watching over your shoulder. The data is yours and yours alone.

So. A new class of apps is enabled by this new SDK. I hope I have inspired you to have a spin with it. If you have read all the way to this, I am very impressed by your perseverance ;-)

Demo solution, as (nearly) always, can be found here.

Edit 26-06-2014: made some minor updates after suggestions from my Finland fellow MVP Jani Nevalainen.

Building multi-resolution popups in an Universal App

With the advent of Windows Phone 8.1 multiple resolution are now also becoming a fact of life for Windows Phone developers (as they already were for Windows Store developers). This has a few side effects, which will require you to think about the size of things that need to cover part of the screen. Particularly you can get into trouble with animations built with visual states, which tend to have fixed number in them. I already dabbled into this when I ported Two Phone Pong to Windows 8.1 and had to make a screen-size independent scroll-into-view pane.

Now, for a demo app I have been working on, I wanted to make a popup that always used 1/3th of the screen. That used to be easy, as we had only one resolution, more or less, and for the rest Windows Phone 8 did some auto scaling. Now it needs a little more work. Very little, as it turned out I almost had all the pieces in place:

  • I already had the UnfoldBehavior, which can be used to let UI elements appear and disappear by ‘folding’ them in or out.
  • I already had the SizeListenerBehavior, which allows me to data bind to the actual width and height of an element

The only thing that was missing was this very simple converter:

using System;
using System.Globalization;

namespace WpWinNl.Converters
{
  public class PercentageConverter : BaseValueConverter
  {
    public override object Convert(object value, Type targetType, 
      object parameter, CultureInfo culture)
    {
      double parmValue;
      if (value is double && double.TryParse(parameter.ToString(), 
                                            out parmValue))
      {
        value = (double)value * parmValue / 100;
      }
      return value;
    }

    public override object ConvertBack(object value, Type targetType, 
      object parameter, CultureInfo culture)
    {
      if (value is double && (parameter is double || parameter is int))
      {
        value = (double)value / 100 / (double)parameter;
      }
      return value;
    }
  }
}

Basically all it does is dividing the incoming value by 100 and multiply it with the parameter value, so if you supply “33” as ConverterParameter is will multiply the incoming value by 0.33, effectively dividing it by 3 (ish).

So now I can define a simple app with a map (for instance), and when the popup is displayed, it always takes the bottom third of the screen. Regardless of screen resolution.

On the 4” WVGA (800x480) emulator this looks like this:

imageimage

While on a 1080p 6” emulator it looks like this:

imageimage

Added bonus: the popup resizes automatically as you rotate the phone. It always takes the bottom third of the screen.

The way to achieve this is pretty simple:

<!-- some stuff snipped -->
<Grid>
  <interactivity:Interaction.Behaviors>
    <behaviors:SizeListenerBehavior x:Name="ContentRootListener"/>
  </interactivity:Interaction.Behaviors>
  <!-- some stuff snipped -->
  
  <Grid Grid.Row="1" Margin="19,9.5,19,0">
    <maps:MapControl>
    </maps:MapControl>
    <!-- the Grid below is the actual popup window -->
    <Grid Height="{Binding WatchedObjectHeight, 
      ElementName=ContentRootListener, Converter={StaticResource PercentageConverter}, 
      ConverterParameter=33}" VerticalAlignment="Bottom" Background="Blue" >
      <interactivity:Interaction.Behaviors>
        <behaviors:UnfoldBehavior RenderTransformY="1" Direction="Vertical" 
                                  Activated="{Binding IsOpen}"/>
      </interactivity:Interaction.Behaviors>
      <StackPanel>
        <TextBlock Text="This is my popup" FontSize="22"></TextBlock>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="It's height is:" FontSize="22"></TextBlock>
          <TextBlock Text="{Binding WatchedObjectHeight, 
            ElementName=ContentRootListener, Converter={StaticResource PercentageConverter}, 
            ConverterParameter=33}" 
            FontSize="22"></TextBlock>
        </StackPanel>
      </StackPanel>
    </Grid>
  </Grid>
</Grid>
  • The top grid has a SizeListenerBehavior. This enables me to bind to the ActualHeight and of the top grid as it changes by binding to WatchedObjectHeight of the SizeListenerBehavior.
  • The height of the popup is set like by actually binding to said value. By using the converter with a parameter of 33 it will – when activated – always use 1/3rd of the screen – or 1/3rd of whatever element your SizeListenerBehavior is sitting on.
  • By setting the UnfoldBehavior’s RenderTransformY to 1 and the Direction to Vertical the popup will open from the bottom up. This is not new, that was already in the original article about UnfoldBehavior.

I have included a small demo solution to show off this little trick. It uses my pre-release version of WpWinNl 2.0.x and a little MVVMLight, but you could use this just as easy from a non-MVVM app. But I still think the beauty of this all is that can be initiated from a viewmodel ;)

In addition, although the demo solution only contains a Windows Phone app, this trick works just as well as on Windows Store apps, as both UnfoldBehavior and SizeListenerBehavior are already in the new WpWinNl NuGet package.

24 June 2014

Messaging class for detecting and broadcasting that your Universal app is running in the background

Some time ago I discovered that you can trap Window.Current.VisibilityChanged in a Windows 8 app to check if the app was running in the background, and that you can use that moment to pause a game and/or save the state to storage. The fun thing is, this now works in Universal apps too, that is – and thus, also on Windows Phone 8.1.Although we can discuss if  the app is really running in the background or that is actually being suspended when it runs on Windows Phone – the mechanism is the same and it can be used to the same end.

So make this more easy to use, I made this very simple class, based upon the MVVMLight MessageBase class:

using Windows.UI.Xaml;
using GalaSoft.MvvmLight.Messaging;

namespace WpWinNl.Messages
{
  public class WindowVisibilityMessage : MessageBase
  {
    public WindowVisibilityMessage(bool visible, object sender = null, 
object target = null) :base(sender, target) { Visible = visible; } public bool Visible { get; protected set; } public static void Setup() { Window.Current.VisibilityChanged += (s, f) => Messenger.Default.Send(new WindowVisibilityMessage(f.Visible)); } } }

and all you have to use it, is to simply put

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
   WindowVisibilityMessage.Setup();
   //Rest of code omitted
 

in the first line of OnLaunched in the App.Xaml.cs

Now anywhere in your app you can now listen for the WindowVisibilityMessage to come by and act on it, like this:

Messenger.Default.Register<WindowVisibilityMessage>(this, p =>
{
  if (p.Visible)
  {
    //do something 
  }
  else
  {
    //do something else
  }
});

And that’s all. The source of this class is already on codeplex and it’s also in the full WpWinNl NuGet package that I released yesterday. Since this class and it’s use is prettysimple and straightforward, I am going to skip a sample solution. A more comprehensive sample where this class plays a minor supporting role is coming soon