Subscribe to the RSS feed then follow me on twitter at @mrlacey (misc) and @wpug (WPDev news)

Wednesday, September 18, 2013

When needing to bind to a platform specific class but the ViewModel is a PCL

This is a less than ideal scenario. I've made by ViewModel a PCL as an aid to making it easier to write "proper unit tests" (i.e. run within Visual Studio) but now I discover I need to add a map to the app and show a dynamic collection of locations (pins) on the map.

<disclaimer>I'm working on a proof of concept app and the requirements are very "flexible" at the moment. Of course I'd plan things better than this in advance under normal scenarios.</disclaimer>

Starting simply, I want to add an ObservableCollection<MyPin> to my VM. But there's a problem.

    public class MyPin
    {
        public GeoCoordinate Coordinate { getset; }
        public string Name { getset; }
    }

The problem is that The GeoCoordinate lives in System.Device.Location and so can't be referenced in the PCL. This means I won't be able to bind to it directly. Frustrating!

frustration

Upon reflection this makes sense. That I'm using a GeoCoordinate is an implementation detail of the UI. It could be displayed as anything. It just makes my life a little bit more complicated.
In reality my class should be more generic:
    public class MyPin
    {
        public double Longitude { getset; }
        public double Latitude { getset; }
        public string Name { getset; }
    }

But this doesn't help with my binding.
So, I need to be able to convert a Latitude and Longitude value into a GeoCoordinate. Sounds like a job for an IValueConverter.

I'm not a big fan of using ValueConverters. They have 2 issues in my mind.
1. They are a performance overhead.
2. They are hard to write coded tests for.

These aren't really issues any more though.

1. This was true in the early days of WP7, where having lots of converters could noticeably impact page loading, but this isn't really a problem any more. You'd have to use loads for this to be an issue on WP8 and I'm only using it where I have to.
2. In this instance I'm only using them for a presentation details though so a lack of automated tests for how locations are displayed on the map isn't a big deal.

So let's add a converter:

public class PinToGeoCoordinateConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object para, CultureInfo culture)
  {
    var pin = value as MyPin;
 
    return pin != null ? new GeoCoordinate(pin.Latitude, pin.Longitude)
                       : new GeoCoordinate();
  }
 
  public object ConvertBack(object valu, Type targetType, object para, CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}
Then I just define my resource:
    <phone:PhoneApplicationPage.Resources>
        <converters:PinToGeoCoordinateConverter x:Key="PinToGeo" />
    </phone:PhoneApplicationPage.Resources>

and then I can use it
    <map:Map x:Name="TheMap">
     <toolkit:MapExtensions.Children>
      <toolkit:MapItemsControl>
       <toolkit:MapItemsControl.ItemTemplate>
        <DataTemplate>
         <toolkit:Pushpin GeoCoordinate="{Binding Converter={StaticResource PinToGeo}}"
                          Content="{Binding Name}" />
        </DataTemplate>
       </toolkit:MapItemsControl.ItemTemplate>
      </toolkit:MapItemsControl>
     </toolkit:MapExtensions.Children>
    </map:Map>

Simples.

All in all this feels like a bit of a kludge. At first it felt like a very bad approach but as time goes on I'm feeling more comfortable with it. I don't know if this is just be getting used to the idea or if it's really not that bad after all.

If you have any better approaches to dealing with this scenario or there are some issues you see with the above I'd love to hear from you.




Are you a Windows Phone developer? If so, you could be getting rewards for the apps you build and the success they achieve by joining Nokia's DVLUP program.

4 comments:

  1. On of my biggest painpoints with PCLs was not being able to use Color in VMs, I mean, how common is that...

    So yeah, as unnecessary as it sounds, bring on HexToColorConverter and HexToSolidColorBrushConverter :)

    ReplyDelete
  2. @Andrej I've been pointed to https://github.com/paulcbetts/splat as a solution for handling Colors, Points and Bitmaps. It's still not a perfect solution but worth a look.

    ReplyDelete
  3. pauliom11:01 pm

    Since GeoCoordinate is not Sealed you can refactor an IGeoCoordinate and RealGeoCoordinate : GeoCoordinate, IGeoCoordinate - this is the one you use at runtime and is interchangeable with GeoCoordinate. You can then create FakeGeoCoordinate : IGeoCoordinate and you can test.

    ReplyDelete
  4. In line Coach Outlet Online is bringing Michael Kors Outlet unique Coach Factory Outlet to a Toms Shoes USA shoe for Cheap Jerseys Spring/Michael Kors Outlet 2014 Coach Factory Outlet, and this Coach Outlet, it’s a Coach Outlet. The Coach Outlet Sale Sandal Giuseppe Zanotti Outlet.Supermodel mom Coach Factory Outlet was Coach Factory Outlet Online being all kinds of hot this weekend Coach Factory Outlet she Coach Store Online out in a Michael Kors Outlet-turning, Celine Outlet I did, I was Celine Bags possessed by Fitflops Flipflops suit madness.Fitflops USA-there string Michael Kors during Michael Kors Store vacation in Tomss Hoes Bahamas. Fitflop Footwear by her family, the 40-year-old looked happy and relaxed - Fitflops Outlet, uh, did we Fitflops Sandals super hot? - as she Giuseppe Zanotti by the pool.I've Giuseppe Zanotti Designer making my own vanilla extract for years. I love it! It's cost-effective, and in my opinion, Vanilla extract is also (easily) the most used extract in my Prada Outlet , sort of pretty (although it kind of looks like spiders too) tastes way better than imitation vanilla extract.

    ReplyDelete