Showing posts with label wpnl. Show all posts
Showing posts with label wpnl. Show all posts

05 January 2015

Binding shapes to the Windows Phone 8.1 Here Maps control

Intro

Every time I meet someone from the Windows Phone Map team (or get into contact with them in some other way) I talk about the importance of being able to data bind shapes to the maps. Things are definitely improving: XAML elements can displayed using data binding out of the box (we used to need the Windows Phone toolkit for that), but Map Shapes alas not. As the saying goes – ‘if the mountain will not come to Muhammad, then Muhammad must go to the mountain' I took up an old idea that I used for Bing Maps on Windows 8 and later converted to Windows Phone 8.0 – and basically adapted it for use in Windows Phone 8.1. Including some bug fixes.

Map display elements recap

You can display either XAML elements on top of the map or use map shapes. XAML elements can be anything, a can be displayed by either adding them in code to the map’s Children property, or by using a MapItemControl, databind it’s ItemSource property to a list object and them define a template for the display using properties from the object bound to the template. Typically, that looks like this:

<Maps:MapItemsControl ItemsSource="{Binding Activities}">
    <Maps:MapItemsControl.ItemTemplate>
        <DataTemplate >
            <Image Source="{Binding Image}" Height="25"
                Maps:MapControl.NormalizedAnchorPoint="{Binding Anchor}" 
                Maps:MapControl.Location="{Binding Position}">
            </Image>
        </DataTemplate>
    </Maps:MapItemsControl.ItemTemplate>
</Maps:MapItemsControl>

Important to know is that these elements are not drawn by the map, but on top of the map, by the UI thread. Typically, they are slow.

Map shapes, on the other hand, are drawn by the map itself, by native code, and therefore fast. You can add them to the map by adding a MapShape child class to the maps’ MapElements properties. You can choose from MapPolyLine, MapPolygon and – new in Windows Phone 8.1 – MapIcon. Data binding is, unfortunately, not something that is supported.

Enter WpWinNlMaps

This time, you won’t have to type or have to look at a lot of code, as I have already published all that’s necessary on NuGet – in the WpWinNlMaps package. You simply add this to your application, and you are ready to go. Mind you, this pulls in a lot of other stuff – the WpWinNl package itself, MVVMLight, and some more stuff. This will enable you to bind view models to the map, have them displayed to and make them ‘tappable’. This is all done with the aid of – you guessed it – a behavior. MapShapeDrawBehavior to be precise.

Concepts

Typically, maps are divided into layers. You can think of this as logical units representing one class of real-world objects (or ‘features’ as they tend to be called in the geospatial word). For instance, “houses”, “gas stations”, “roads”. In Windows Phone, this is clearly not the case: all MapShapes are thrown into one basket – the MapElements property. In WpWinNlMaps, a layer roughly translates to one behavior attached to the map.

A MapShapeDrawBehavior contains a few properties

  • ItemsSource – this is where you bind your business objects/view models to
  • PathPropertyName – the name of the property in a bound object that contains the Geopath describing the object’s location
  • LayerName – the name of the layer. Make sure this is unique within the map
  • ShapeDrawer – the name of the class that actually determines how the Geopath in PathPropertyName is actually displayed
  • EventToCommandMappers – contains a collection of events of the map that need to be trapped, mapped to a command on the bound object that needs to be called when the map receives this event. Presently, the only events that make sense are “Tapped” and “MapTapped”.

A sample up front

Before going further into detail, let’s do a little sample first, because theory is fine, but code works better, in my experience. So I have a little class containing a viewmodel that has a Geopath, and Name, and a command that can be fired:

public class PointList : ViewModelBase
{
  public PointList()
  {
    Points = null;
  }
  public string Name { get; set; }

  public Geopath Points { get; set; }
  
  public ICommand SelectCommand
  {
    get
    {
      return new RelayCommand<MapSelectionParameters>(
        p => DispatcherHelper.CheckBeginInvokeOnUI(() => 
        Messenger.Default.Send(new MessageDialogMessage(
          Name, "Selected object", "Ok", "Cancel"))));
    }
  }
}

Suppose a couple of these things are sitting in my main view model’s property “Lines”, then I can simply display a number of blue violet lines by using the following XAML

<maps:MapControl x:Name="MyMap" >
  <mapbinding:MapShapeDrawBehavior LayerName="Lines" ItemsSource="{Binding Lines}" 
       PathPropertyName="Points">
  
      <mapbinding:MapShapeDrawBehavior.EventToCommandMappers>
        <mapbinding:EventToCommandMapper EventName="MapTapped" 
             CommandName="SelectCommand"/>
      </mapbinding:MapShapeDrawBehavior.EventToCommandMappers>
      
      <mapbinding:MapShapeDrawBehavior.ShapeDrawer>
        <mapbinding:MapPolylineDrawer Color="BlueViolet"/>
      </mapbinding:MapShapeDrawBehavior.ShapeDrawer>
      
  </mapbinding:MapShapeDrawBehavior>
</maps:MapControl

So:image

  • Objects are created from the collection “Lines”
  • The name of the layer is “Lines” (this does not need to correspond with the name used in the previous bullet)
  • The property containing the Geopath for a single object in the list “Lines” is called “Points”
  • When the event “MapTapped” is detected on one of these lines, the command “SelectCommand” is to be fired. Mind you, this command should be on the bound object. Notice this fires a MessageDialogMessage that can be displayed by a MessageDialogBehavior. Basically, if all the parts are in place, it will show a message dialog displaying the name of the object the user tapped on.
  • This object is to be drawn as a blue violet line.

The result being something as displayed to the right.

Map shape drawers

These are classes that turn the Geopath into an actual shape. You get three out of the box that can be configured using a few simple properties.

  • MapIconDrawer
  • MapPolyLineDrawer
  • MapPolygonDrawer

To draw an icon, line or polygon (duh).  The key thing is – the drawers are very simple. For instance, this is the drawer that makes a line:

public class MapPolylineDrawer : MapLinearShapeDrawer
{
  public MapPolylineDrawer()
  {
    Color = Colors.Black;
    Width = 5;
  }

  public override MapElement CreateShape(object viewModel, Geopath path)
  {
    return new MapPolyline { Path = path, StrokeThickness = Width, 
                             StrokeColor = Color, StrokeDashed = StrokeDashed, 
                             ZIndex = ZIndex };
  }
}

There is only one method CreateShape that you need to override to make your own drawer. You get the viewmodel and the Geopath (as extracted by the MapShapeDrawBehavior and you can simply mess around with it.

The drawer class model is like this:

image

Trapping events and activating commands with EventToCommandMapper

By adding an EventToCommandMapper to EventToCommandMappers you can make a command get called when an event occurs. You can do that easily in XAML as displayed in the sample. Basically only events that have a MapInputEventArgs or TappedRoutedEventArgs can be trapped. In most real-world cases you will only need to trap MapTapped. See the example above how to do that. Keep in mind, again, that although the event is trapped on the map, the command is executed on the elements found on the location of the event.

There is a special case though where you might want to trap the “Tapped” event too – that is when you mix and match XAML elements and MapShapes. See this article for background information on that particular subject.

Some limitations and caveats

  • Even for MapIcons the PathPropertyName needs to point to a Geopath. This is to create a common signature for the CreateShape method in the drawers. Geopaths of one point are valid, so that is no problem. If you provide Geopaths containing more than one point, it will just use the first point.
  • Although the properties are read from bound objects, those properties are not bound themselves. Therefore, an object that has already been drawn on the map will not be updated on the map if you change the contents of the Geopath. You will need to make sure the objects are in an ObservableCollection and then replace the whole object in the collection to achieve that result.
  • If you use a method like mine to deal with selecting objects (firing messages), your app’s code will need to deal with multiple selected objects – since there can be more than one object on one location. My sample solution does clearly not do that. All objects will fire a message, but only one will show the message dialog. A better way to deal with it would be
    • Make a message that contains the MapSelectionParameters that are supplied to the command that is fired on select (see sample code)
    • Have the MainViewModel collect those messages, and decide based upon the SelectTime timestamp what messages are the result of one select action and should be displayed together.
  • In professional map systems the order of the layers determines the order in which elements are drawn. So the layers that are drawn first, appear at the bottom, and everything that’s drawn later on top of it. In Windows Phone, the Z-index of each element determines that. So be sure to set those in the right order if you want to appear stuff on top of each other.
  • Be aware that MapIcons are a bit of an oddball. First, they are drawn using a ‘best effort’. In layman’s terms, this means that some of them won’t a appear if they are too close together. If there are a lot close together, a lot won’t appear. This will change while you zoom and pan, and you have no way to control it. Furthermore, MapIcons don’t always show on top of other shapes even if you specify the Z-index to be higher.

Conclusion

imageThe sample solution shows the drawing of icons, lines and polygons using the binding provided by WpWinNlMaps. You can tap on a map element and the name of the tapped element will display in a message dialog. This should give you a running start in using this library.

Although there are quite some limitations with respect to the binding, mainly caused by the nature of how the map works (you cannot bind to a command that is to be called when you tap the element – you can just provide the name of the command, just like the path property) I think this library makes using the map a lot easier – at least in MVVM apps. I am using this library extensively in my latest app Travalyzer.

Happy mapping!

22 December 2014

A behavior to show a MessageDialog from a MVVMLight viewmodel in Universal apps–with callbacks

Of course you are now all writing MVVM based apps, after all I have been advocating that for years, and you are listening this here old venerable MVP, right? ;). Anyway, some UI interactions between UI and viewmodel can seem to be a bit complicated, but these kinds of problems are usually pretty simple to solve with a combination of a behavior, the MVVMLight messenger, and a message containing a callback. And as I hate to write things more than once, I  made this into a reusable behavior. It ain’t rocket science, but it’s nice and clean.

I start with a class holding the actual message, and in this class file I have defined a callback delegate as well:

using System.Threading.Tasks;
using GalaSoft.MvvmLight.Messaging;

namespace WpWinNl.Behaviors
{
  public class MessageDialogMessage : MessageBase
  {
    public MessageDialogMessage(string message, string title,
                                string okText, string cancelText,
                                MessageDialogCallBack okCallback = null,
                                MessageDialogCallBack cancelCallback = null,
                                object sender = null, object target = null)
                                : base(sender, target)
    {
      Message = message;
      Title = title;
      OkText = okText;
      CancelText = cancelText;
      OkCallback = okCallback;
      CancelCallback = cancelCallback;
    }

    public MessageDialogCallBack OkCallback { get; private set; }
    public MessageDialogCallBack CancelCallback { get; private set; }
    public string Title { get; private set; }
    public string Message { get; private set; }
    public string OkText { get; private set; }
    public string CancelText { get; private set; }
  }

  public delegate Task MessageDialogCallBack();
}

It’s a basic MVVMLight BaseMessage child class, with properties for various texts, and two optional callbacks for OK and cancel actions.

The behavior itself is, as behaviors go, pretty simple:

using System;
using System.Diagnostics;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using GalaSoft.MvvmLight.Messaging;

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

    private async void ProcessMessage(MessageDialogMessage m)
    {
      bool result = false;
      var dialog = new MessageDialog(m.Message, m.Title);

      if (!string.IsNullOrWhiteSpace(m.OkText))
      {
        dialog.Commands.Add(new UICommand(m.OkText, cmd => result = true));
      }

      if (!string.IsNullOrWhiteSpace(m.CancelText))
      {
        dialog.Commands.Add(new UICommand(m.CancelText, cmd => result = false));
      }

      try
      {
        await dialog.ShowAsync();
        if (result && m.OkCallback != null)
        {
          await m.OkCallback();
        }

        if (!result && m.CancelCallback != null)
        {
          await m.CancelCallback();
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine("double call - ain't going to work");
      }
    }
  }
}

This being once again a SafeBehavior, it simply starts to listen to MessageDialogMessage messages. When one is received, a MessageDialog is constructed with the message and title to display, as well as an optional Ok and Cancelbutton – and callback. If you send a message, you can provide optionally provide simple method from your viewmodel to be called by the behavior when Ok or Cancel is called, thus providing a two-way communication channel. Mind, though, all this is async, which has a curious side effect: if you send another message before the user has clicked Ok or Cancel, this will raise an exception.This will be displayed in the Visual Studio output window while you debug, but it won’t show up in release, and your message won’t be displayed either – so you need to carefully control sending messages, and not throw them out like there’s no tomorrow.

I have made a little sample app – a Universal app of course, because there have been some pretty clear hints by Microsoft this is the way to go forward. You will notice everything worthwhile is the shared project, up to the MainPage.xaml. People who were present at the latest Lowlands WpDev day last October will remember my fellow MVP Nico Vermeir saying in his talk “don’t do that, there’s pain in there”, and while this is true, it’s an ideal thing for lazy demo writers.

I started out with a blank Universal app, and moved the MainPage.Xaml and it’s companion MainPage.Xaml.cs to the shared project. Then I brought in my WpWinNl project that, amongst other things, drags in MVVMLight and everything else you need. Then I created this whopping complex viewmodel:

using System.Threading.Tasks;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using WpWinNl.Behaviors;

namespace SampleMessagePopup
{
  public class MainViewModel : ViewModelBase
  {
    public ICommand MessageCommand
    {
      get
      {
        return new RelayCommand(
          () => 
            Messenger.Default.Send(new MessageDialogMessage(
              "Do you really want to do this?", "My Title", 
              "Hell yeah!", "No way", 
              HellYeah, Nope)));
      }
    }

    private async Task HellYeah()
    {
      Result = "Hell yeah!";
    }

    private async Task Nope()
    {
      Result = "NOOOO!";
    }


    private string result = "what?";
    public string Result
    {
      get { return result; }
      set { Set(() => Result, ref result, value); }
    }
  }
}

imageimageIf you fire the command, it will show a dialog that looks like the left on these two screens (on Windows Phone) and if you press the “no way” button it will show the very right screen. A few things are noticeable:

  • Both methods are async, although they don’t implement anything asynchronous. That’s because I wanted to be able do awaitable things in the callback and a contract is a contract – were not making JavaScript here. Only tools like ReSharper (highly recommended) will make you notice it, but you can ignore it for now.
  • You might notice the callback methods are private but still the behavior is apparently able to call these methods. This, my dear friends who grew up in the nice era of managed OO languages that shield you from the things that move below you in the dark dungeons of your processor, is because you basically give a pointer to a method – and that’s accessible anywhere. Your compiler may tell you it’s a private method, but that’s more like it has a secret telephone number – if you got that, you can access it anywhere ;-). Us oldies who grew up with C or Assembler can tell you all about the times when boats were made of wood and men were made of steel and the great ways you can shoot yourself in the foot with this kind of things. If you want to make you app testable it makes more sense to make the methods public, by the way, but I could not let the opportunity to show this great example of the law of leaky abstractions pass.

But I digress, I know, that is also a sign of age ;)

The Xaml is of course also pretty simple – as this app does not do much:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" 
    xmlns:Behaviors="using:WpWinNl.Behaviors"
    x:Class="SampleMessagePopup.MainPage"
    DataContext="{StaticResource MainViewModel}">
  <Interactivity:Interaction.Behaviors>
    <Behaviors:MessageDialogBehavior/>
  </Interactivity:Interaction.Behaviors>
  <Page.BottomAppBar>
    <CommandBar>
      <AppBarButton Icon="Accept" Label="go ask!" 
                    Command="{Binding MessageCommand}"/>
    </CommandBar>
  </Page.BottomAppBar>

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
  	<TextBlock Text="{Binding Result}" HorizontalAlignment="Center" 
                   VerticalAlignment="Center" FontSize="56"/>
  </Grid>
</Page>

Notice the behavior sitting on the page itself. For obvious reasons, it’s the logical place to put. You can also put it on the top grid. But whatever you do, use only one per page. They all listen to the same message, and if you put more of them on one page you will get an interesting situation where multiple behaviors will try to show the same MessageDialog. I have not tried this, but I assume it won’t be very useful.

To make this work, by the way, you need of course to declare your viewmodel in App.Xaml. You have no other choice here, as the App Bar sits at the top level of the page, the button calls the command and thus the resource must be one level higher, i.e. the app itself.

<Application
    x:Class="SampleMessagePopup.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SampleMessagePopup"
    xmlns:system="using:System">

  <Application.Resources>
    <local:MainViewModel x:Key="MainViewModel" />
  </Application.Resources>
</Application>

Again, if you use something like ReSharper a simple click on the declaration in MainPage.Xaml will make this happen.

So, that’s all there is to it. You won’t find the code for this behavior in the solution, as it is already in WpWinNl. Just like the previous one ;). As usual, a sample solution is provided, but in inspired by my fellow MVP Diederik Krols I’ve have decided that going forward I will publish those on GitHub.

23 October 2014

Making the Application Bar display on of top of the UI in Windows Phone 8.1 Store Apps

In Windows Phone 7, 8 and 8.1 Silverlight apps this is very easy: you just set the Opacity of the Application bar to any value less than 1 as described here, and the app does not reserve space for the app bar – it just displays the bar on top of the main UI like this:

image

The problem is, if you set the opacity of what is now called the CommandBar in Windows Phone 8.1 Store apps, the Application bar is translucent indeed - which you can see if you open it - but the apps still reserves space for it in it’s closed state:

image

The fix for this is surprisingly easy, but also pretty hard to find if you don’t know what you are looking for. In the end I got a tip by mail from my famous fellow MVP Rudy Huyn. You just add the following, not very obvious line of code to your app. I added it to my App.Xaml.cs, just before the line “Window.Current.Activate();”

 ApplicationView.GetForCurrentView().SetDesiredBoundsMode(
   ApplicationViewBoundsMode.UseCoreWindow);

Right. And then you get what you want (as is displayed in the first image). And once you enter this line of code into a search engine, then you find hits enough, dating back to even April. But well, that did not help me much. Hopefully this simple article will save someone else a fruitless seach ;)

To make this code compile, you will need to add a “using Windows.UI.ViewManagement;” on top of your file. And although it is in fact an article about code, I will skip the sample download app this time – for just one line of code it feels like a bit of overkill.

Update – be aware that not only the Application Bar now falls over the UI, but the status bar on top as well. So you may want to take that into account when designing your UI: keep some extra space at the top, or make in partially translucent as wel. Thanks to my fellow MVP Shawn Kendrot for pointing me to this article that he has written some time ago

13 August 2014

Querying the Windows Phone 8.1 map when there are child objects over it

With the Windows Phone 8.1 SDK came (yet again) an improved Map Control. This brought, among other things, the MapIcon. In ye olde days, the map could only draw lines and polygons natively – when you had to draw icons you had to add child objects to the map itself, which were drawn by the UI thread and not by the map. This is slower and eats more resources.

imageThe new map still offers this possibility. And sometimes we need it, too, for a couple of reasons. First of all, a MapIcon can only display an image and an optional label. Second, MapIcons are drawn on the map using a ‘best effort’, which mean overlapping icons don’t get displayed at all and – worse – if you query the map, using the FindMapElementsAtOffset method, they are not found either.

So in some cases we just need to resort to drawing XAML elements by adding to the map’s Children collection – an option, which luckily has been improved tremendously as we now, for instance, can data bind these elements using the MapItemsControl, as explained by my smart fellow MVP Shawn Kendrot. Before 8.1, we needed the Windows Phone Toolkit for that.

But I noticed something very odd. I have been trained to use the MapTapped event to trap the location where the user tapped, as the Tapped event is being trapped by the map itself. It never fires. So I used MapTapped, and then FindMapElementsAtOffset to query the map;

But to my dismay I also discovered that the MapTapped event does not fire either when you tap on a location where a child object is displayed. Ergo – if you tap on the cross where the Windows Phone logo is displayed, nothing happens. So how am I to find out what’s underneath there?

After some trashing around I stumbled upon the answer – if you tap on a child element that’s on the map – not the MapTapped, but the Tapped event fires. “The event that never fires” comes to the rescue. In addition, the Tapped event on the child object itself fires. So I created the following method to query the map:

private void QueryMap(Point offset)
{
  foreach (var obj in MyMap.FindMapElementsAtOffset(offset))
  {
    Debug.WriteLine(obj.GetType());
  };
}
The regular method to trap MapTapped:
private void MyMap_OnMapTapped(MapControl sender, MapInputEventArgs args)
{
  Debug.WriteLine("MyMap.MapTapped occurred");
  QueryMap(args.Position);
}

And a method to trap Tapped when that occurs, and that also routes to the QueryMap method, with a little help from the GetPosition event method:

private void MyMap_OnTapped(object sender, TappedRoutedEventArgs e)
{
  Debug.WriteLine("MayMap.Tapped occurred");
  QueryMap(e.GetPosition(MyMap));
}

And because the events never fire simultaneously, you will see the map finds one PolyLine when you tap on a line just next to the symbol, will and it fill find two lines (the crossing of both) when you tap on the symbol- but never will you get a double hit from both events.

By attaching to the Tapped event of the Child object I can also detect if the symbol itself is tapped:

var childObj = new Image { 
  Source = new BitmapImage(new Uri("ms-appx:///Assets/wplogo.png")) };
MapControl.SetNormalizedAnchorPoint(childObj, new Point(0.5, 0.5));
MapControl.SetLocation(childObj, p5);
MyMap.Children.Add(childObj);
childObj.Tapped += ChildObj_Tapped;



void ChildObj_Tapped(object sender, TappedRoutedEventArgs e)
{
  Debug.WriteLine("ChildObj.Tapped occurred");
}

And thus we can find everything on the map, provided you attach the right methods to the right events. The MapTapped/Tapped combo of the map is an odd one but once you know how to do it – a few extra lines of code does it all.

A demo app demonstrating the whole concept can be found here.The only thing it does is write things to the debug console when you do something, so pay attention what happens there ;-)

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.

22 June 2014

Introducing WpWinl 2.0.0 (prerelease version)

Today I have decided to take the plunge – I have released an early version of WpWinNl 2.0.0 to NuGet. This introduces quite some changes.

To start with, WpWinNl now consists of two packages:

  • WpWinNlBasic, which contains all the stuff that is not dependent on MVVMLight. This includes a lot of behaviors, converters and utilities, including a lot of animation stuff.
  • WpWinNl proper, which is dependent on WpWinNlBasic and does pull in MVVMLight.

So if you just want to continue using WpWinNl like you used to do, nothing much is going to happen apart from the fact that you pull in two NuGet packages in stead of one. But if you for some odd reason does not like MVVMLight, or don’t use it can now use all my stuff that does not rely on MVVMLight by pulling in WpWinNLBasic only. I have received several request to that end (most vocally by Dutch DPE Rajen Kishna), so there it is.

If you, by any chance, use WpWinNl on Universal apps or Windows app, you are pulling in a profound change under the hood. For those type of apps, all the code I have written so far is sitting inside a PCL, including the behaviors. To that end, I use my previously released version of IBehaviorPortable, that uses a trick to make it possible to write cross-platform behavior (as described here).

This is a pre-release version as I said, for the simple reason that there are a few known issues:

  1. I am not entirely sure of the Bluetooth stuff. Although phone to phone seems to work, phone to PC does not, at least not under Windows Phone 8.1. I still have to get to the bottom of this
  2. Not all behaviors and utilities made it from Windows Phone 8.0 to 8.1. This includes the behaviors to check for updates, reminding the user to review, and some stuff that Timmy Kokke contributed some 1.5 years ago.

As a bonus, I also released a third package, that allows you to bind polygons, lines, and the new MapIcons to the new Windows Phone 8.1 here maps control. You can find this package by looking for WpWinNlMaps, and it basically is an update to the principle I describe here for Windows Phone 8.0. No sample code yet folks – been a bit busy lately.

I am pretty sure this all works pretty well (barring the mentioned issues), but being a engineer, I don’t say it’s done until it’s really done. So, therefore – prerelease. Terms and conditions may apply. Your mileage may vary. And stuff like that.

If you discover any issues, run into trouble, or have suggestions to improve things - please feel free contact me.

21 May 2014

Windows Phone emulator–“Unable to create a route between the waypoints”

The Windows Phone 8.1 emulator has a beautiful new option: if you want to simulate a route you don’t have to put in a gazillion points anymore, you just input two (or some more if you want specific waypoint), the emulator automatically calculates a route and off you go, in this case from my home to some location near Amsterdam:

image

Only for some people it does not work out so well. I have seen some reports of people getting this popup, whatever two points they entered, even if those two were very close together with an obvious route:

image 

Today my friend Matteo Pagani ran into the same problem – and using a remote access tool I was able to have a look at his computer and determine once and for all the root cause of this. And it’s very simple – Matteo had set his computer to English like me, but still had the European decimal number setting. For those who are not familiar with that – when an European wants to write “a hundred thousand and a half” he writes “100.000,5” where an American typically writes “100,000.5”. Decimal point and comma are reversed. Whoever thought up this reversal, well let’s stay civilized here but I don’t have very warm feelings toward him or her, let’s put it that way. For some reason, in Geographical Information Systems territory, this is a fairly common problem. I have set my computer to the American number style for longer than I care to remember so I never ran into it.

To fix this, you have to adopt the American style of numbers in Windows. Go to your Control Panel, search for number and select “Change date, time or number formats”

image

Then in the next dialog

image

“Decimal symbol” should be set to . (dot) and “Digit grouping symbol” to , (comma). For extra fun, the difference is hard to spot. Close Visual Studio and the emulator, restart Visual Studio, bring up the emulator again, and presto.

I know – this affects all programs in Windows so now your Excel sheets will show up in American style. Don’t shoot the messenger, I am just reporting the problem and a work-around. It’s not the end of the world. I don’t think much people will spend days and days simulating routes ;-)

02 April 2014

Code sharing strategies between Windows Phone 8.1 and Windows 8.1 with the new Universal Windows apps

With the announcement of the new SDK for Windows Phone Microsoft now really starts to stress the companionship of Windows and Windows Phone, and makes it a lot easier to build apps that run on both platforms. Windows Phone apps now reside under ‘Store Apps’ and although you can still write Windows Phone only apps, it’s pretty clear to me what the preferred way to go for new Windows Phone apps is

image

Two new kinds of Windows Phone apps

Let me make one thing clear: no-one is going to push you. Windows Phone 8.1, like it’s predecessor, will run 8.0 apps fine. You can go on re-using the skillset you have acquired, still using the XAML style you are used to. In fact, Microsoft stresses this point even more by including Windows Phone Silverlight 8.1 apps, which are a bit of a halfway station: your XAML largely stays the same, but it gives you access to the new APIs. Yet I feel the crown jewel of the new SDK is the new Universal Windows app and, in it’s slipstream, the enhanced PCL capabilities. But once again – no-one is forcing you this way. Microsoft are very much about going forward, but also about protecting your existing skills and assets.

One solution, two apps

One thing up front: ‘one app that runs everywhere’ is a station that we still have not reached. You are still making two apps – one for Windows Phone, one for Windows. In this sense, it’s basically the same approach as before where you used code sharing with linked files. That was quite a hassle, and now Visual Studio supports a formal way to share files between projects. This makes maintaining oversight dramatically easier, and it gets rid of the confounded “This document is opened by another project’ dialog too. Plus – and that’s a very big plus – the code you can use on both platforms has become a lot more similar.

Going universal

imageOne warning in advance – if you going for the Universal Windows app, you’re going all the way. It means that for your Windows Phone app in most cases you are basically writing a Windows 8 app - using XAML and APIs that are familiar for Windows Store apps programmers, but not necessarily for Windows Phone developers. If you already have some experience writing Windows Store this won’t be a problem. If you have never done that before, some things may look a bit different.

So, I have created a new blank Universal Windows app and it shows like displayed on the right:

Initially, it only shows the App.Xaml.cs as shared. This has one great advantage already – you can go in and disable the frame rate counter for both apps in one stroke :-):

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                //this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

Switching contexts

If you go through the shared App.Xaml.cs you will notice a few more things: at several places in the file it says #if WINDOWS_PHONE_APP, and I also want to point out this little thing on top, the context switcher.

image

You can set the context switcher to ‘MyNewApp.Windows and you will see the Windows app code greyed out. This way, you can very quickly see which code is executed in which version and which not

image

Sharing code – sharing XAML

So I went to the Windows Store app, opened Blend, added some text and two tool bar buttons:

<Page
    x:Class="MyNewApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyNewApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
  <Page.BottomAppBar>
    <CommandBar>
      <AppBarButton Icon="Accept" Label="AppBarButton" Click="AppBarButton_Click"/>
      <AppBarButton Icon="Cancel" Label="AppBarButton"/>
    </CommandBar>
  </Page.BottomAppBar>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <TextBlock HorizontalAlignment="Left" 
                 Height="37" Margin="90,53,0,0" TextWrapping="Wrap" 
                 Text="Hello World" 
                 VerticalAlignment="Top" Width="383" FontSize="29.333"/>

    </Grid>
</Page>

And added some code behind.

private async void AppBarButton_Click(object sender, RoutedEventArgs e)
{
  var m = new MessageDialog("Hello world");
  await m.ShowAsync();
}

Now this won’t make for a spectacular app. If you run it, it will basically show:

imageimage

It amaaaaazing, right ;-)? But then I went a bit overboard – I imagemoved MainPage.xaml and imageMainPage.xaml.cs to the Shared project, and removed it from the Windows Phone 8.1 project. Run the Windows Store App again – still works. Run the Windows Phone 8.1 app, and sure enough…

Now this may seem pretty cool – and in fact it is - but it would not be something I would recommend using just like that. Windows Phone is a different beast, the way people use a phone app differs from how they use a Store app on a tablet, and usually you have to think different about how the layout works on a tablet. Case in point – the app bar. Windows Phone has only room for four buttons. The Secondary Commands show up as menu items, not as buttons. The Top bar does not show up at all. So blindly copying a UI from Windows Phone to Windows Store and back is not a smart thing to do. But the fact that it works, is in itself pretty cool.

Sharing code – in a more practical way

In practice, I have found you almost never share whole pages between phone apps and store apps, for a number of reasons:

  • Phone design does not always translate easily to tablet design and vice versa (as pointed out above).
  • For phone, space is a premium, and you don’t want to drag along all kinds of stuff that’s only used on a tablet - think super-high-res stuff, or all kinds of elaborate XAML constructions to accommodate that
  • If you use controls on one platform that simply are not present on the other, or if you use native controls (for example, maps)

To maximize code sharing, you can for instance use partial classes. That works like this: in your code behind MainPage.Xaml.cs you declare the class “partial”.

namespace MyNewApp
{
  /// <summary>
  /// An empty page that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();
    }
  }
}
And then in the shared project you create a new file MainPage.Xaml.cs (or MainPage.cs), with just this:
namespace MyNewApp
{
  /// <summary>
  /// An empty page that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();
    }
  }
}

And this still gives the same result. Partial classes in shared projects can be pretty powerful. From the partial class in shared code you can call for instance back to methods in the non-shared portion, provided that those called methods are present in both the non-shared portions of the class (so both the MainPage.Xaml.cs). You can even call methods in referenced PCLs. Just keep in mind that in the background it just works like shared files and you can do a lot to minimize duplication.

More ways of sharing

Another way of sharing code is putting most of it in the shared portion – even stuff that’s not present on both platforms – but then using the #ifdef WINDOWS_PHONE_APP and #ifdef WINDOWS_APP directives. This is largely a matter of preference. For smaller classes with little differences I tend to choose this route, for larger classes or code behind files I tend to go for partial classes.When I am working on stuff that is particularly phone-related, I don’t want my code cluttered by Windows code, and vice versa.

A third way of sharing pieces of UI would be creating user controls in shared code. They can be reused within pages that are in itself not shared.

Finally – don’t forget that everything can be shared in the shared images. Apart from XAML and code this includes, for instance:

  • Images
  • Resource files (styles, templates, localization, etc)
  • Data files

And PCL?

In the past, I have never been a fan of PCL, because of their limitations. This has been greatly improved by the new model and I actually start to like it. If you make a PCL for use in Windows 8.1 and Windows Phone 8.1 you can put almost everything in it that can be stuffed in a shared project, including user controls – although of course you can’t do elaborate partial classes callback tricks into non-shared code. This is because a PCL needs to stand on itself. So only everything that is available in both platforms fits in, so for instance almost everything map-related is out (with a few notable and very important exceptions: Geolocation (GPS tracking) and Geofencing (that is now available on Windows Phone too!).

Still – PCL is only useful if you are building stuff that

  • Needs to be reusable over multiple different apps
  • Needs to be usable on both Windows Phone and Windows Store

With this respect, there is not much difference in building platform-specific libraries and distributing them vi NuGet. This is more for the advanced programmer who is starting to build his own toolkit. This means you, by the time you are working on your third app :-)

Code sharing recap

  • Code, XAML or assets that can be shared within one app for both platform can go into a shared project. For code that does not fit entirely you can use
    • Partial classes
    • #ifdef directives
  • Code, XAML or assets that can be shared over multiple apps for both platform can go into a PCL

Conclusion

Build for Both has become a lot easier. You still have to deliver two apps, but making them as one has become a lot easier. Making clever use of the of partial classes and #ifdef makes it easier too, although this requires some thinking. Still, you have to take into account how both platforms behave differently.

A new exiting story for Windows Phone and Windows developers has begun.

The ‘demo solution’, which is hardly worth it’s name in this case, can be downloaded here.

23 February 2014

A behavior to replace LayoutAwarePage in Windows Store and Windows Phone apps

Sometimes I think up things all by myself, sometimes I have to read something first to let the ole’ light bulb in my brain go ‘ping’. This post is of the 2nd category, and was inspired by this brilliant piece by C# MVP Iris Classon who is – apart from a very smart and respected coder – also a living and shining (not to mention colorful) axe at the root of the unfortunate gender bigotry that is still widespread in the IT world – a lot of people still think seem convinced “women can’t code, if they do they do it badly, and those who do are socially inept, boring and ugly”. Which is demonstrably untrue – coding requires just a brain and determination - but I am convinced it still shies a lot of brain power out of IT.

Anyway – what I basically did was take Iris’ idea an turn it into – you guessed it – a behavior, to make it more reusable.

To demonstrate how it works, I created the following Store app with a very compelling UI:

image

There is only one text of 75pt there. And then I created three Visual States:

  • Default, which does basically nothing
  • Medium, which changes the font size to 50pt
  • Small, which changes the font size to 25pt

How this is done is amply explained by Iris’ post so I don’t feel very compelled to repeat that here. After creating the states I brought in my WpWinNl nuget package, and added my new SizeVisualStateChangeBehavior to the page. Then I added three entries to “SizeMappings” to the behavior by clicking on the indicated ellipses on the right:

image

  • “Default” with width 801
  • “Medium” with width 800
  • “Small” with width 500

From 801 up to infinity the the Default state will be used (showing the text in it’s default size), between 800 and 501 the Medium state will be used (50pt), and from 500 and lower, the Small state (25pt). And voilá, automatic sizing of items done by filling in some boxes in Blend – or typing in some XAML in Visual Studio if that’s more of your thing. Notice you can add any number of Visual States for any range of widths, just as long as there is one “Default” state that has a width that’s one higher than the largest none-default width. Notice SizeVisualStateMappings can have any name you like as well, as long as they correspond with names of Visual States.

For extra credit, by the way, I made this behavior attachable to Control objects rather than Page, so it can be used inside (user) controls as well. And with some #ifdef directives it also works for Windows Phone, which might come in handy with more and more of resolutions entering the Windows Phone arena.

As to how this behavior works, it’s not quite rocket science. First, we have this hugely complex class :-P that holds one SizeVisualStateMapping:

namespace WpWinNl.Behaviors
{
  public class SizeVisualStateMapping
  {
    public string VisualState { get; set; }
    public int Width { get; set; }
  }
}

The actual behavior’s setup almost immediately shows what I am doing – I simply latch on to the SizeChanged event of the object that the behavior is attached to:

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
#if WINDOWS_PHONE
using System.Windows;
using System.Windows.Controls;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
#endif

namespace WpWinNl.Behaviors
{
  public class SizeVisualStateChangeBehavior : SafeBehavior<Control>
  {
    protected override void OnSetup()
    {
      AssociatedObject.SizeChanged += AssociatedObjectSizeChanged;
      base.OnSetup();
      UpdateVisualState();
    }
    
    private void AssociatedObjectSizeChanged(object sender, SizeChangedEventArgs e)
    {
      UpdateVisualState();
    }
  }
}
The core of the behavior’s functionality is the UpdateVisualState method:
private void UpdateVisualState()
{
  if (SizeMappings != null)
  {
    SizeVisualStateMapping wantedMapping = null;
    var wantedMappings = 
SizeMappings.Where(p => p.Width >= AssociatedObject.ActualWidth); if (wantedMappings.Any()) { wantedMapping = wantedMappings.OrderBy(p => p.Width).First(); } else { var orderedMappings = SizeMappings.OrderBy(p => p.Width); if (AssociatedObject.ActualWidth < orderedMappings.First().Width) { wantedMapping = orderedMappings.First(); } else if (AssociatedObject.ActualWidth > orderedMappings.Last().Width) { wantedMapping = orderedMappings.Last(); } } if (wantedMapping != null) { VisualStateManager.GoToState(AssociatedObject, wantedMapping.VisualState,
false); } } }

Which simply tries to find a SizeVisualStateMapping that’s fit for the current width of the associated object. If it finds that, it tells the VisualStateManager to go to that state, which proceeds to do the actual work. And that’s basically all. All that's left are an Dependency Property SizeMapping of type List<SizeVisualStateMapping> SizeMappings that holds the actual mapings, and a Cleanup method that detaches the behavior from the SizeChanged event again.

Full details, and a working solution including this behavior, can be found here. If you run this app in split screen and slowly makes it’s window width smaller, you will notice the text getting smaller. Be aware that the change only fires when you actually let the window divider control go – as long as you keep it active (by touching or dragging it) nothing will happen.