WP7Contrib – FindaPad and the fastest list in the west

FindaPad is the first App to be built from the ground up using the WP7Contrib. In fact, the process of building FindaPad led to the creation of the WP7Contrib. FindaPad is a property searching experience that provides users with the ability to view the available properties in a chosen area and also allows users to gain a better understanding of the facilities and demographical information of the area. It’s more than a list of properties.

My plan is to do a small series of blog posts that cover off particular areas that caused some degree of pain during the experience of creating FindaPad. The solutions for such problems have been added into the WP7Contrib allowing other WP7 App creators to use these building blocks and enable them to create high performance, and high quality apps faster.

In this post I want to take you on a journey through the App and touch on some of the more technical aspects of what’s happening behind the curtains. I will also cover off some of the UI interactions and layout used and the reasons why.
The initial startup screen was designed to be as simple as possible allowing the user to immediately start searching for properties. We also took into consideration recent searches. This area of functionality moved around a bit, it was also ditched at one point, and then finally reincarnated and came to rest on this initial page.In order to keep the page clean, on initial startup we decided to hide the recent searches area, as it provides no real useful information at this time and leaving the recent search title on the page was confusing. Recent searches is therefore only displayed after the user has started searching.

In order to perform a search the user has a number of options; search by current location; search by postcode; search by place name; and if you really want to then you can use a Latitude and Longitude. Repeat users can use the recent searches area to jump straight back to a previous search. The page does have some other options in the app bar which, provide quick access options. Remember this is all about navigating as efficently as possible – because of this we have provided a settings and favourites button. Functionality needs to be thumb friendly. Again, the controls moved around a bit during iterations but they now live on the home page to cater for the repeat usage scenarios. We could have removed the favourites button on initial startup however we made the decision that adding buttons to the app bar was confusing. Stateful buttons are cool and great for feedback.

The settings page, is an interesting one and an area where if you have feedback it would be useful to start a general conversation around best practices for app settings.

For this experience the functionality provides the user with the ability to change the country where they want to perform a search and the default check box for Geo Location based apps. The other options provide the ability to change the amount of data that is received by the user based on the type of connection.

A very important note for other people developing mobile applications which take advantage of 3rd party services, is that if you are solely reliant on the emulator then you are living in a false economy. In the real world 3G and Wifi are going to be the most widely used connections. Slower connection speeds will effect the experience that users have when interacting with the app. Testing on the handset and the different connection types are essential for ensuring that the experience is maintained.

Therefore, to address this problem the App allows the user to change the default amount of data delivered to the handset in order to not degrade their experience. In some ways I feel that we could bake this into the app and simplify this experience. However, it’s also helpful for more advanced users. (So it would be great to hear your feedback in order to discuss whether you find these types of settings options useful for data heavy apps or if you feel that that the app should take care of such things.)

The Favourites page, as you may very well have guessed is a list of favourite properties; this view is consistent with the results list in order to provide a consistent look and feel. Selecting a favourite from the list navigates users into the details area of the App. Recently the favourites functionality was redesigned allowing users to view all of their favourite properties on a map.

Once the user has chosen the way in which they want to search for properties, selecting the rent or buy options performs a search and navigates the user to the search results page. The layout of the results was designed to take advantage of iconography in order to help simplify the visualisation of the data. The information displayed is just enough for the user to make an informed decision about selecting a property.

I would have to say that this area of the app took up the majority of time and it’s where app creators can really take advantage of the WP7Contrib. On first glance you look at the list and think well that’s not too tricky; an image some vector graphics and some text. What you then very quickly come to realise is that slamming your UI with data that’s coming from a 3rd party service turns out not to be such a great idea. In one way it’s arguable that the platform should provide better support for this type activity and in the Mango release some of these problems have been addressed.

I have attempted to sum up details of these learnings below, but will also go into more technical details in this series of posts. (If you would like more information I presented at Techdays UK where we talk about data driven Apps on WP7) Originally I started off with a list box and a rather complex data template, which caused a lot of problems. So I simplified the layout and what was being displayed. Converters are not great when it comes to performance; their usage was scaled back and these conversions done in the lower levels of the App. These small tweaks helped with performance but did not cure it. What resulted was an interesting journey of building some reusable components that can be found in the WP7Contrib and I would highly recommend using them if you are building a data intensive App or if you’re seeing performance issues with loading a list(s) of data. By using data virtualisation it provides a far more controlled mechanism that can be used to render data to the screen. These fixes solve the issue around getting data but we still need to improve how UI virtualisation is done and from a high level this comes in 2 forms. Firstly, loading the images is all done asynchronously to help improve load and rendering times and secondly this approach needs to be layered with prioritising which images are in the viewport in order to maintain a responsive experience. Therefore, the App monitors which images are currently being displayed and deals with these before the other images. Those images that are out of view are paused. Once the visible images are rendered, the App resumes downloading of the other images out of view.

The next change was swapping from a list box control to a long list selector control found in the toolkit designed which has been specifically to deal with larger amounts of data. The final, part of the puzzle was controlling when to add more data, the app only updates the UI with more items when the user is not scrolling. With all these elements in place the experience is a compelling one.

Now, why was this so much effort, well it’s all based around the type of experience that I wanted to create where by the user can infinitely scroll the list and does not have to manually say “get more”. I know that we can do better than a “get more” button appearing at bottom of a list, and yes it does result in more work. However, the resulting experience is more enjoyable and means that the user simply keeps scrolling down the list while the app responds by getting more properties.

There are lots of interesting technical details that I will go into in a separate post around what is happening behind the scenes here which should prove helpful to others.

On selecting a property the users are navigated to a details page, originally this was going to be a panorama control but as the majority of the apps that I have built or been involved in building you start out with good intentions. However, due to heaviness of the control this usually results in using a pivot control in place of the panorama.
The details page brings together some of the useful information that helps users gain a better understanding of what the area is like. This information is visualised by using charts. Visiblox chart controls are the ones that we use, they are very lightweight but pack a big punch which means that you can get these charts to render in a pivot control. Sweet!

The details page displays all of the information that we are given from Nestoria. One of the issues of working with 3rd party API’s is that you lose complete control over the data with regards to its integrity, yes we can paginate and create complex queries but we are not guaranteed complete data, and this is illustrated in the screen shot where Nestoria are unable to send details on the number of bedrooms or bathrooms. This is frustrating. However, the sooner we come to the realisation that this is a real world situation and design for it the better. The way it’s done here is to hide the artwork so that when the data is incomplete these are hidden from the user. Selecting the “view on” button navigates the user to the estate agent that has been aggregated by Nestoria. Unfortunately, the information shown on these web pages are not available via the Nestoria API. So in order to retain the user there is a specific page within the app that uses a browser control so that we don’t lose the user. This experience is far more fluid than navigating the user to the native browser where they leave the app and the experience feels disjointed and clunky.

The crime and house price pivot pages contain the visualisation of the information from the UK Police API for crimes in the surrounding area. The Nestoria API provides the data for average prices in the local area. Both charts look great and load in a reasonable time. The line chart is a tricky one. The key is fundamental to understanding the data being visualised in the chart, however in its expanded state and with the maximum number of average prices returned the layout is a little cluttered. I have been thinking about collapsing the key index and expanding when the user touches the index. (If you have thoughts on this we would love to hear them, all for more general thoughts on using charts or data visualisation in your app it would be great to discuss those as well.)

The app bar on this page provides some actions that navigate the user to the other screens; property map; route map; and actions for email; and adding a property to favourites. These options are there to help with the immersive experience that we are trying to create. The experience here is that once the user has found a property of interest there is a stepping off point into other interesting areas of the App.

The property map page visualises the data about the area surrounding the property, and provides the user with different options for viewing different facilities, these include, medical centres; pubs; restaurants; coffee shops; and shopping centres. The idea here is to visualise this data in the most useful way possible and when dealing with properties and facilities the map metaphor works best. There are a predefined set of options here. We are very interested in hearing from users with regards to how useful these options are and if you could customise these would you want the ability to do so.

The route map page is all about helping you get from where you are to the property that you have found. For me this is one of the killer aspects of the app and uses, sensors and services to create a great experience. There are options to change the mode of transport from walking to driving.

And that concludes the journey. As I mentioned at the start FindaPad is built on top of the WP7Contrib and hopefully illustrates the art of the possible when incorporating this into you WP7 app. So, I would strongly recommend that if you are thinking about creating a WP7 to check out the open source project and the supporting blog posts and samples.
Finally, none of this would have been possible without the human compiler Ollie Riches and great design eye of Nick Harewood. They, have some great posts coming up that talk in depth about particular areas of the app.

Expression Blend 4 does not start after installing the NET Framework 4.5 Developer Preview

Over the last couple of days I have been trying out different combinations for app development on the Metro/WinRT platform and one of these involved installing VS 2011 Ultimate on to my main box that runs Win 7. Unfortunately Blend and the VS 11 Ultimate Developer Preview bits don’t play together out of the box. This is a known issue, and following the steps below will fix the issue.

You can Copy and Paste the commands below.

Open a command prompt window with administrative privileges and then run the following commands:

%windir%\Microsoft.NET\Framework\v4.0.30319\ngen uninstall “%ProgramFiles(x86)%\Microsoft Expression\Blend 4\Microsoft.Expression.Framework.dll”

%windir%\Microsoft.NET\Framework\v4.0.30319\ngen uninstall “%ProgramFiles(x86)%\Microsoft Expression\Blend 4\Microsoft.Expression.Blend.dll”

%windir%\Microsoft.NET\Framework\v4.0.30319\ngen uninstall “%ProgramFiles(x86)%\Microsoft Expression\Blend 4\Microsoft.Expression.Project.dll”

If you have installed Expression Blend 4 SP1, you must also uninstall the native image of the Microsoft.Expression.WindowsPhone.dll file from the cache by using the following command:

%windir%\Microsoft.NET\Framework\v4.0.30319\ngen uninstall “%ProgramFiles(x86)%\Microsoft Expression\Blend 4\Microsoft.Expression.WindowsPhone.dll”

 

What’s also rather interesting is that when installing VS11 Ultimate on to a Win 7 box you are not able to create Metro apps.

Big thanks to Steve White and Joanna Mason from the Expression Blend team for helping to resolve this issue.

Metro Controls – Jump Viewer

After an amazing week at //Build, I’ve been busy playing with the new controls, which I have to say are fantastic! Ollie and I know the pain first hand when it comes to building a Silverlight TUI (Touch User Interface) it’s not a great story and IMHO the controls are not ready. I may still post my thoughts on this experience, I’ve been holding back as I really don’t want to be dragged into the Silverlight is DEAD! debacle and this post could be taken in this way, however it will give you context around why we are so pleased that there is a new story and that one is awesome. But while I think about posting my experiences of building TUI on slates running Win 7, I’ve been putting together notes on the controls and thought that these may be beneficial to others so my objectives are to walk through some of the new controls and peel the layers like an onion. So, we can then go deep on certain topics.

So without further ado please say a big HELLO! to the Jump Viewer which is currently my favourite control. The interactions are stunning and performance is awesome! Before I start to dig in we should take a look at the finished control. The first screen shot is of the Jump Viewer when it first loads up in its zoomed in state and the second screen shot is taken when we peform an inwards pinch gesture which zooms out and the semantic zoom kicks in replacing the view with higher level details so that we can easily jump to another position in the Grid.

 

 

Note:- there are some anti-aliasing issues that happen periodically, not sure why this happens but I will update the post when I know more.

 

For more background reading on semantic zoom check out the guidelines for semantic zoom and also the sample in the SDK.

What I really like about the Jump Viewer is that it uses composition, allowing you to simply wrap up other controls that you may have used previously in order to deliver an immersive experience when interacting with the visualised data. In order to build a better understanding of the control we need to look at the Xaml. Lets start by concentrating on the JumpView which is the part of the control that is activated when we zoom out.

I have added my notes into the Xaml and hopefully this is a better way of groking the Xaml rather than snippets and dialogue, this way you can copy and paste the Xaml into your app and retain the notes.



 <!--
The jump view is the visual effect when we use semantic zoom the pinch-in gesture
The grid view items panel is set to a wrapgrid
Which renders a list of category names
-->
<JumpViewer x:Name="jumpViewer"
        Grid.Row="1"
        Margin="120,0,0,0">
        <!--
        The jump viewer jump view
        -->
        <JumpViewer.JumpView>
                <GridView Foreground="White">
                <GridView.ItemTemplate>
                <!--
                Data template used to visualise what we want to display when zoomed out
                In our case we are showing some group text
                -->
                <DataTemplate>
                        <TextBlock Text="{Binding Name}"
                        FontFamily="{StaticResource SemiBoldContentFontFamily}"
                        FontSize="{StaticResource HeaderLargeFontSize}"
                        Foreground="{StaticResource PageForegroundBrush}" />
                </DataTemplate>
                </GridView.ItemTemplate>
                <GridView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <!-- 
                                Positions child elements sequentially from left to right or top to bottom. 
                                When elements extend beyond the container edge, elements are positioned in the next row or column.
                                You can change the Maximum rows or columns to change the visual layout when zoomed out
                            -->
                            <WrapGrid ItemWidth="114"
                                      ItemHeight="114"
                                      MaximumRowsOrColumns="6"
                                      VerticalChildrenAlignment="Center" />
                        </ItemsPanelTemplate>
                </GridView.ItemsPanel>                    
                <!--
                Note when we change the item container style the target type is ListViewItem not GridViewItem
                -->
                <GridView.ItemContainerStyle>
                    <Style TargetType="ListViewItem">
                        <Setter Property="Margin"
                                Value="6" />
                        <Setter Property="Padding"
                                Value="12" />
                        <Setter Property="BorderBrush"
                                Value="{StaticResource PageForegroundBrush}" />
                        <Setter Property="BorderThickness"
                                Value="1" />
                        <Setter Property="HorizontalContentAlignment"
                                Value="Center" />
                        <Setter Property="VerticalContentAlignment"
                                Value="Center" />
                    </Style>
                </GridView.ItemContainerStyle>
                </GridView>
            </JumpViewer.JumpView>

Below is an illustration of the above Xaml and how the composite parts fit together.


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

What is very cool is the new Wrap Grid which provides the ability to change the layout of Jump View in the code above I do this.

<WrapGrid ItemWidth="114"
    ItemHeight="114"
    MaximumRowsOrColumns="6"
    VerticalChildrenAlignment="Center" />

In order to change the layout of the grid we can simply change the number of Maximum Rows or Columns, for example changing this property to 1 will change the layout to look more like the standard search control in Metro. Therefore, a quick tweak with how many rows or columns you want means that you can change the experience depending on the content being visualised. I will cover off the Wrap Grid in a future post.

Next we need to look at the content part of the Jump Viewer.

<!--
    The content view renders the detailed items
-->
<JumpViewer.ContentView>
    <GridView ItemsSource="{Binding Source={StaticResource cvs2}}"
              IsCrossSlideEnabled="True">
    <!--
        Main content template
    -->
    <GridView.ItemTemplate>
        <--
           Data template used to display the data 
        -->
        <DataTemplate>
            <StackPanel Orientation="Horizontal"
                Margin="12,10,0,0"
                HorizontalAlignment="Left">
                <Image Source="{Binding Image}"
                       Height="60"
                       Width="60"
                       VerticalAlignment="Center"
                       Margin="0,0,10,0" />
                <TextBlock TextWrapping="Wrap"
                           Style="{StaticResource ItemTitleStyle}"
                           Width="240"
                           VerticalAlignment="Center"
                           Text="{Binding Title}"
                           HorizontalAlignment="Left"
                           FontFamily="{StaticResource SemiLightContentFontFamily}" />
             </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
    <!--Group Style this will allow for the grouping visual effects that we want-->
    <GridView.GroupStyle>
        <GroupStyle>
        <!--Group Style Header template defines what controls we use in the header-->
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text='{Binding Name}'
                           Foreground="{StaticResource PageForegroundBrush}"
                           Margin="0,0,36,0"
                           FontSize="{StaticResource HeaderLargeFontSize}"
                           FontFamily="{StaticResource SemiBoldContentFontFamily}" />
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
        <!--Group Style Container Style -->
        <GroupStyle.ContainerStyle>
            <Style TargetType="GroupItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GroupItem">
                    <!--Change the orientation of the panel to change where the Group Header is positioned -->
                        <StackPanel Orientation="Horizontal">
                            <ContentPresenter Content="{TemplateBinding Content}" />
                            <ItemsControl x:Name="ItemsControl"
                                          ItemsSource="{Binding GroupItems}" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        </GroupStyle.ContainerStyle>
        <GroupStyle.Panel>
            <ItemsPanelTemplate>
            <!-- 
                Provides a grid-style layout panel where each tile/cell can be variable size based on content.
            -->
            <VariableSizedWrapGrid Orientation="Vertical"
                                   MaximumRowsOrColumns="6" />
            </ItemsPanelTemplate>
        </GroupStyle.Panel>
        </GroupStyle>
    </GridView.GroupStyle>
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <!--VirtualizingStackPanel VirtualizationMode="Recycling" -->
                <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
                    <Button Visibility="Collapsed" />
        </GridView>
    </JumpViewer.ContentView>
</JumpViewer>

 
As you can see the Content section of the Jump Viewer comprises another control, in this case a Grid View, which provides the horizontal scrolling experience. A new feature for Metro is the ability to apply a Group Style on both the List and Grid View controls which provide the ability to group the data if your data model supports it. I will go into more detail about Group Styles in a future post. For now what we should understand is that when providing a Group Style we need to ensure that we provide a data template that will visualise the data in the header template and we can change the orientation of the layout by changing the Stack Panel in the Item Container Style from Vertical to Horizontal.

The Grid View also needs a data template for the items and there is also another new layout control called the Variable Sized Wrap Grid which is being used to layout the items in the Grid View. Once again I am loving this new layout and I will talk in more detail about the control in a future post. The most important thing for now is to understand that like the Wrap Grid, we can change the orientation and the Maximum Rows Or Columns properties which effect the layout of the items in the Grid. Sweet!

You may have also noticed that I have commented out the Virtualizing Stack Panel, I had problems when I used this, not sure why this is and when I find out more details I will update the post.

Enjoy!

WP7Contrib – Bing Service Wrapper Part V Imagery

The Imagery Service provided by the Bing Maps Rest Service is quite beastly as it supports a large number of permutations that can be requested from the endpoint. In order to successfully wrap up these calls we have encapsulated the url templates used and provided by the service. As with Routes there are a number of sub categories that then have further permutations as to what you can request from the endpoint. The Imagery service is very powerful but we believe that its most important usage on the phone is that it allows you to calculate a route and then have this route visualised as an image rather than you have to process the points and plot them onto a map like we saw in the Routes Service. Therefore, its very useful for improving performance in your app.

Once again you will see very familiar code when compared to the other services Location, Route and Search and our good mate Criterion Factory makes the construction of the request super simple, all of our requests are done using Rx and all the code you see here can be found in the spikes folder up on Codeplex.

The two main categories and their sub categories for the Imagery service are :-

Static Maps

  • Get a map that is centered at a specified point.
  • Get a map that shows a specified area based on a bounding rectangle supplied.
  • Get a map that is centered at a specified point and displays a route.
  • Get a map that displays a route without specifying a center point, this allows the caller to specify a route by using waypoints. When a map area or center point and a zoom level are not specified, a map area is chosen to optimise the display of the route.
  • Get a map that is based on a query.



The sample code has an example of each of the sub categories which will take a look at in this post. In the sample app there are some list selectors where you can pick different options and then request the type of static map you require.

As I mentioned at the start the Imagery service is very powerful and also helps to improve performance as what is returned from the Bing Maps endpoint is an image that we can display in the visual tree.

Lets start with the get a static map that is centered at a specific point. This does what it says on the tin. In the code below we set the current location of the device using the location service and then we ask the Criterion Factory to create a request to deal with creating an image for the specified location. The static map property is a Uri and this is bound up the image source of an image control in the View.

private void ExecuteSelectCenterPointCommand()
{
    this.currentLocationObserver = this.locationService
        .Location()
        .ObserveOnDispatcher()
        .Subscribe(geoCoordinate =>
        {
            var criterion = CriterionFactory.CreateImageryUrlForCenterPoint(
                        this.imagerySetInUse,
                        geoCoordinate,
                        this.CurrentlySelectedZoomLevel,
                        new Size(456, 535));

            this.StaticMap = this.bingMapsService.ImageryUrlForCenterPoint(criterion);
        });
}

A couple of things to note with regards to the parameters being passed to the method being called on the factory :-

  • this.imagerySetInUse is the imagery set of which there are 3 supported options;Aerial; Aerial with labels; and Road without imagery.
  • geoCorodinate is the current location of the device.
  • this.CurrentlySelectedZoomLevel is the zoomlevel.
  • new Size(456, 535) is the requested size of the image that we want returned from the endpoint.

 

 


There are a number of overloaded methods so that you can pick the one which suits your needs best, this is also replicated for the other methods exposed for each of the subcategories.

Next up, get a static map that is for a calculated Route between waypoints and centered at a point.

private void ExecuteSelectCenterPointWithRouteCommand()
{
    var start = new GeoCoordinate(40.77, -73.98);
    var end = new GeoCoordinate(41.51, -87.39);

    var wayPoints = new List<WayPoint> 
    {
        new WayPoint { Point = start },
        new WayPoint { Point = end } 
    };

    var criterion = CriterionFactory.CreateImageryUrlForCentrePointWithRoute(
        this.imagerySetInUse,
        this.modeOfTravelOptionInUse,
        start,
        this.CurrentlySelectedZoomLevel, 
        wayPoints, 
        new Size(456, 535), 
        this.avoidOptionInUse);

    this.StaticMap = this.bingMapsService.ImageryUrlForCenterPointWithRoute(criterion);
}

A couple of things to note with regards to the parameters being passed to the method being called on the factory :-

  • this.imagerySetInUse is the imagery set of which there are 3 supported options;Aerial; Aerial with labels; and Road without imagery.
  • this.modeOfTravelOptionInUse is the mode of travel of which there are 3 supported option; Driving, Walking and Transit.
  • start is the point around which the image is centered.
  • this.CurrentlySelectedZoomLevel is the zoom level that we want the image
  • wayPoints is a list of GeoCoordinates that make up the Route that you want to travel
  • the avoidOptionInUse is the road types that you want to avoid there are 4 options; Highways; Tolls; minimise Highways and minimise Tolls.

 

 

 

 

 

 

Next up, get a static map for a specific area that has a calculated route.

private void ExecuteSelectSpecificAreaWithRouteCommand()
{
    const double south = 37.317227;
    const double west = -122.318439;
    const double north = 37.939081;
    const double east = -122.194565;

    var start = new GeoCoordinate(south, west);
    var end = new GeoCoordinate(north, east);

    var wayPoints = new[] 
    {
        new WayPoint { Point = start },
        new WayPoint { Point = end }
    };

    var criterion = CriterionFactory.CreateImageryUrlForSpecificAreaWithRoute(
        this.imagerySetInUse, 
        this.modeOfTravelOptionInUse, 
        wayPoints, 
        new LocationRect(north, west, south, east));

    this.StaticMap = this.bingMapsService.ImageryUrlForSpecificAreaWithRoute(criterion);
}


A couple of things to note with regards to the parameters being passed to the method being called on the factory :-

  • this.imagerySetInUse is the imagery set of which there are 3 supported options;Aerial; Aerial with labels; and Road without imagery.
  • wayPoints is a list of GeoCoordinates that make up the Route that you want to travel
  • new LocationRect(north, west, south, east) is a bounding box that we create using lat and long values to represent the area.

 
 

 

 

 

Next up, get a static map for a specific area.

private void ExecuteSelectSpecificAreaCommand()
{
    const double south = 37.317227;
    const double west = -122.318439;
    const double north = 37.939081;
    const double east = -122.194565;

    var criterion = CriterionFactory.CreateImageryUrlForSpecificArea(
            this.imagerySetInUse, 
            new LocationRect(north, west, south, east));
    this.StaticMap = this.bingMapsService.ImageryUrlForSpecificArea(criterion);
}

A couple of things to note with regards to the parameters being passed to the method being called on the factory :-

 

  • this.imagerySetInUse is the imagery set of which there are 3 supported options;Aerial; Aerial with labels; and Road without imagery.
  • new LocationRect(north, west, south, east) is a bounding box that we create using lat and long values to represent the area.

 

 

 

 

 

 
 

 
 

 

Next up, get a static map for a specific calculated Route.

private void ExecuteSelectRouteCommand()
{
    var start = new GeoCoordinate(40.77, -73.98);
    var end = new GeoCoordinate(41.51, -87.39);

    var wayPoints = new[] 
    { 
        new WayPoint { Point = start },
        new WayPoint { Point = end } 
    };

    var pushPins = new List<PushPin>();

    var criterion = CriterionFactory.CreateImageryUrlForRoute(
        this.imagerySetInUse, 
        this.modeOfTravelOptionInUse,  
        wayPoints, 
        DateTime.Now, 
        this.optimizeRouteOptionInUse, 
        pushPins, TimeType.Departure);

    this.StaticMap = this.bingMapsService.ImageryUrlForRoute(criterion);
}

 

And the final option for static maps is the ability to get a map showing the query result centered on a map, in our example this is the Space Needle in Seattle.

private void ExecuteSelectQueryCommand()
{
    var criterion = CriterionFactory.CreateImageryUrlForQuery(
        this.imagerySetInUse, 
        "space needle,seattle");

    this.StaticMap = this.bingMapsService.ImageryUrlForQuery(criterion);
}

 

And that completes the overview for each of the pillars that compose the Bing Maps REST API Location, Route and Imagery services. Hopefully you have found them useful and they help to supplement the code example in the Spikes folder for WP7C.

As always it would be great to hear your feedback good and bad to help make these wrappers fit your requirements.

Enjoy!

WP7Contrib – Bing Service Wrapper Part IV Location Simplified

Based on feedback around my first post in this series of talking about how to use Location I thought that I would revisit how you can use this really cool bit of stuff in your app. When I first wrote the original post it was much more bare bones however, there were lots of unanswered questions when I did and could be taken out of context. Therefore I wanted to reiterate how easy it is for you app to incorporate Geo Location features and enhance the User Experience.

So, lets start off with some new code and how you can pretty much copy and paste this boiler plate code into your app and start to take advantage of Geo Location. Ollie has done some refactoring of the defined constructors making the implementation simpler. Which means; if you are not using Dependency Injection; or MVVM; or just want something very specific from the service, these new constructors will give you the ability to do just that.

The code below can be found in the BingMapsLocationDemo folder under spikes of the WP7C along with lots of other samples including the original code that exercises the Bing Maps Wrapper.

First, we need an instance of the BingMapsService.

this.bingMapsService = 
    new BingMapsService("Your credentials id", "Your app id");

Next, we need to use our good friend the CriterionFactory that will do all the work required to generate the request that will be sent to the endpoint. There are a couple of flavours for Location, depending on what you want to do; for finding out the address of a GeoCoordinate you can use CreateLocationSearchForPoint; or for finding out the full address from a partial one you can use CreateLocationSearchForAddress.

var criterion =
    CriterionFactory.CreateLocationSearchForAddress(this.postCode.Text);

Finally, we need use Rx to perform the async call. Using the instance of the BingMapsService we call the method which in our case is SearchForLocationUsingAddress that takes the criterion created by the factory as a parameter.

this.bingMapsService.SearchForLocationUsingAddress(criterion)
        .ObserveOnDispatcher()
        .Subscribe(result =>
        {
         this.address.Text = result.Locations[0].Address.Locality;
         this.address.Text += Environment.NewLine;
         this.address.Text += result.Locations[0].Address.PostalCode;
         this.address.Text += Environment.NewLine;
         this.address.Text += result.Locations[0].Address.AdminDistrict;
         this.address.Text += Environment.NewLine;
         this.address.Text += result.Locations[0].Address.CountryRegion;
        });

Boom! Your done!

Hopefully, second time round this post is clearer and a far more succinct illustration of how to use the Location in your app. We will also continue to add some new projects into the Spikes folder to illustrate the other condensed constructors for Search, Imagery and Routes.

WP7Contrib – Tombstoning Part II The View Model

In the last post I introduced the idea of separating the tombstoning into two separate responsibilities, the View and the View Model. Each has a different responsibility; the View for specific information to enhance the User Experience and the View Model for databound properties.

Last time it was all about the View so now its time for the View Model to step up and we can hear her story. As we have already hinted, the View Model tombstoning tends to be all about your properties that you have exposed so that you can databind these in Xaml or code behind to visual controls.

The View Model mechanism is slightly more involving as the process is a little more manual as you will have to explicitly define which properties in the View Model you want to be tombstoned. It also has a dependency on the Storage Service interface. We typically wire this in via a couple of methods called IsBeingActivated and IsBeingDeactivated and they live in a base View Model that all the View Models in the app subclass.

    protected override void IsBeingActivated(IStorage storage)
    protected override void IsBeingDeactivated(IStorage storage)

If you’ve checked out some of the samples on the WP7C codeplex site you maybe aware that we tend to create a class called ViewModelBaseWP7 which subclasses the MVVM Light ViewModelBase. For me its the class I copy first when creating a new project as its contains a whole bunch of plumbing that we use in the app, what always comes next is the ViewModelLocator and Bootstrapper classes, anyway if you want to use them awesome if not no worries.

In the sample code you will find a View Model called MainViewModel that all the Views are databound too. The rule here is to add each of these databound properties to the overridden methods and the IStorage interface provides the Read and Write methods. You will notice in the sample code that I am only stashing basic types, you can stash more complex types however you need to ensure that they can be serialised by Silverlight Serializer. Ollie has a great post on how to do this using the IsCachable method.

protected override void IsBeingActivated(IStorage storage)
{
    var tbv = storage.Read<string>("TextBoxValue");
    var cbv = storage.Read<bool>("CheckBoxValue");
    var pbv = storage.Read<string>("PasswordBoxValue");
    var rbv = storage.Read<bool>("RadioButtonValue");
    var sv = storage.Read<int>("SliderValue");
    var tgbv = storage.Read<bool>("ToggleButtonValue");

    DispatcherHelper.CheckBeginInvokeOnUI(
        () =>
        {
            this.TextBoxValue = tbv;
            this.CheckBoxValue = cbv;
            this.PasswordBoxValue = pbv;
            this.RadioButtonValue = rbv;
            this.SliderValue = sv;
            this.ToggleButtonValue = tgbv;

            storage.Clear();
        });
}

protected override void IsBeingDeactivated(IStorage storage)
{
    storage.Write("TextBoxValue", this.TextBoxValue);
    storage.Write("CheckBoxValue", this.CheckBoxValue);
    storage.Write("PasswordBoxValue", this.PasswordBoxValue);
    storage.Write("RadioButtonValue", this.RadioButtonValue);
    storage.Write("SliderValue", this.SliderValue);
    storage.Write("ToggleButtonValue", this.ToggleButtonValue);
}

The next thing that we need to do is the plumbing for activating and deactivating the View Models, now depending on what sort of technique you’re using then you have a couple of choices on how you want to do it. We prefer to do this in the View Model Locator where we can find out what is happening to the View Models. In order to sniff out what state our View Models are in we can use the Phone Application Service who can tell us what is happening about the state of the app. Therefore the implementation can be done by adding in a check in the constructor to see if the StartupMode is Activate and hooking up to the Deactivated event. There are numerous ways you can implement the activate and deactivting hooks the approach I have used here is the one we use.

And there you go your done! The View Model will now tombstone all the properties that are supplying data being visualised and when combined with the View state tombstoning we have complete support for tombstoning in the app.

WP7Contrib – Tombstoning Part I The View

Yes I know, that old chestnut what more could there be to say? Well quite a lot actually and my intentions are to do this as a two part blog post. Where we’ll cover off how to use the new tombstoning mechanism found in the WP7Contrib (WP7C).

But, hang on you said that WP7C already supports tombstoning as you provide an interface called IStorageService which is a wrapper for using Isolated Storage on the phone?
And, yes, that is correct normally we would have a bootstrapper and use Dependency Injection to setup the application scaffolding. However, this approach is only useful when you are looking to persist data that you have in the View Model, it’s simple and symmetrical allowing you to express your intentions clearly.

However, the Storage Service was designed to be used with properties which are observable ( INotifyProperyChanged) and databound in the UI either via Xaml or code behind. These properties are used to control and manipulate state and logic being processed by your VM. Cool, this works for data and it’s a trivial exercise to get this implemented as I will show you in the next post.

But what about the View?

Exactly, up until now in our projects we have exposed additional properties on the View Model to deal with View state. Its something that, Ollie and I have been meaning to refactor and recently we took on the challenge and the results make it a trivial exercise for you to add View state tombstoning into your app.

Let me explain, View state is purely about the status of the controls in the Visual Tree. This status has nothing directly to do with any data bound to the control.

Therefore, you’re not going to find tombstoning support for TextBox, CheckBox, PasswordBox, RadioButton or ToggleButton in the View state tombstoning. The reason for this is we assume you’re databinding to the IsChecked Dependency Property and the responsibility of managing the state lies with the View Model. You may be databinding directly to your model objects and I have no issues with this in certain cases, but in both of these cases we find that the state management and logic of the app is not the responsibility of the View.

The View state tombstoning supports Panorama, Pivot & ScrollViewer*. Thanks to composition we don’t need an explicit tombstoner for ListBox as the only state we are interested in saving is the scroll position handled by the ScrollViewer tombstoner. If you want to create a custom one then you can by implementing the ICanTombstone interface and register your new tombstoner.

* From Aug SL Toolkit Long List Selector uses a ScrollViewer

So, the tombstone support offered is very specific for example; when scrolling a list we want to remember what the ScrollViewer’s offset was; when panning either the Pivot or Panorama we want to remember which item you were viewing; and if you have a list in one of your Pivot or Panorama items we want to remember the offset is was well.

The implementation of the View state tombstoning is boiler plate so once you have copied and pasted the code below into you app your done! The View state classes can be found in WP7Contrib.View.Controls. Tombstoner so you will need a reference to WP7C.View.Controls.

To restore the view state wire up the loaded event and call RestoreState.

       this.Loaded += (sender, args) =>; this.RestoreState();

To persist the view state override the OnNavigatedFrom method and call PersistState.

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
       base.OnNavigatedFrom(e);
       this.PersistState();
}

Boom! Your done!

So, you may be asking why the RestoreState happens in the Loaded and not in the OnNavigatedTo method override. Well actually it started its life their, however when we wired in the original tombstoning we found that because our View Model was asynchronously loading data from a service into the View Model sometimes it had not finished by the time the OnNavigatedTo method was invoked. Therefore it lives in the Loaded event as we can pretty much guarantee that the controls will be bound to our properties exposed by the View Model. You may not want to have this level of complexity however I am pretty certain that you will want to have the flexibility of using asynchronous calls in either your View Model or the services that it uses.

The inspiration and tombstoning concepts can be found here in the TombstoneHelper developed by Matt Lacey. While I really like the conceptual idea that my pages should be able to automatically support tombstoning and it just happens automagically. The reality is that when using a pattern such as MVVM one of the principles we sign up for is Separation of Concern between the View and the View Model and because of this its conceptually simpler to allow each to only be responsible for there area of concern, View = UI, View Model = data.

The View state tombstoner would not be possible if it weren’t Colin Eberhardt and his amazing Linq to Visual Tree class.

Next I will cover off using the View Model state tombstoning and illustrate how you can combine both approaches to provide a complete tombstoning solution for your app.

WP7 Contrib – Bing Maps Rest API Wrapper Part III Search

In the previous post we looked at how you can incorporate the Calculate Route service into your WP7 app, using bolier plate Rx code and a simple pattern.

Next up is Search and how to search an area of the map control programmatically. For example, there is a great deal of data out there and a lot of this can be mapped down to a Geo Coordinate, therefore it’s a great opportunity for us to provide richer experiences that layer this information onto a map allowing users to see what is near to them. A simple and effective way to do this is by using the Bing API. Just to be clear, what I am referring to is recreating the same experience that you have on WP7 when you select the search button on your handset. However we can now incorporate this directly into your application so that users don’t have to leave the experience just to use search via a map.

Now, strictly speaking the ability for you to search in a particular bounding rectangle on a map is not part of the Rest API it is in fact part of the Bing API V2 . However, in an attempt to help reduce complexity and provide a simple and consistent implementation approach we have decided for the time being, that it should live with the other API calls that we make. At this moment in time we only support search via a map and so this also feels like the right place for it to live as all the bits also are map specific services.

This is rather important, you will need to generate another key if you want to use this Bing service.

Using this service is exactly the same as the other services that we have discussed so far, and hopefully the code is starting to look more familiar. Just like the Location, Route and Imagery services we follow the same pattern; we need some types; we need a factory to build the request criterion; and we need a service method that takes the generated criterion as a parameter to be implemented using boiler plate Rx code, as seen previously. You can use the users location and then you can rock from here, or you can use the postcode; pass this to the location service which will return you a Geo Coordinate; pass this Geo Coordinate along with the bounding rectangle of the map, the Bing service will then search only within this bounding rectangle for your search term.

The search service in the sample has a UI consisting of; a map control to display results; a textbox to enter search keywords; and a button to initiate the search. The button is wired up to a command which is responsible for making the request.

The code below uses the Criterion Factory to help us build the criterion that we need to pass to the API in this particular case we call the Create Search For Services and pass it the bounding rectangle that we want the search to happen in. Once the factory has created the criterion we use the boiler plate Rx code to make the service call.

private void ExecuteBingSearchCommand()
{
    try
    {
        this.SearchResult = null;
        var criterion = CriterionFactory.CreateSearchForServices(
                new LocationRect(this.CurrentDeviceGeoCoordinate, 5, 5),
                this.SearchQuery,
                CultureInfo.CurrentCulture);

        this.bingMapsService.SearchForServices(criterion)
            .ObserveOnDispatcher()
            .Subscribe(this.ProcessBingSearchResponse, FailedSearch, CompletedSearch);
    }
    catch (Exception exn)
    {
        MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message),
         "Services Search", MessageBoxButton.OK);
    }
}

The code required to process the response.

private void ProcessBingSearchResponse(SearchResult result)
{
    if (result == null)
    {
        return;
    }

    this.SearchResult = result;
}

Again as with the other services, the root object that you need to be aware of is called the Search Result. The Xaml below show you how to plot these search results on to the map control. Here I am using the MapItemsControl and databinding its Items Source to the collection of Results that comes back from the request. For completeness I have also included the Data template that is being used to plot the map push pin.

<DataTemplate x:Key="MapPinPhoneBookDataTemplate">
    <Microsoft_Phone_Controls_Maps:Pushpin Location="{Binding Path=Location}">
        <Microsoft_Phone_Controls_Maps:Pushpin.Content>
            <Grid HorizontalAlignment="Left">
                <Border>
                    <TextBlock Text="{Binding Business}" />
                </Border>
            </Grid>
        </Microsoft_Phone_Controls_Maps:Pushpin.Content>
    </Microsoft_Phone_Controls_Maps:Pushpin>
</DataTemplate>

<Microsoft_Phone_Controls_Maps:Map x:Name="searchresultsnearbymap"
        ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
        Center="{Binding CurrentMapSearchCenterPoint, Mode=TwoWay}"
        ZoomBarVisibility="Collapsed"
        CopyrightVisibility="Visible"
        AnimationLevel="UserInput"
        HorizontalContentAlignment="Stretch"
        VerticalContentAlignment="Stretch"
        Grid.RowSpan="2"
        Background="{StaticResource SemiOpaqueDarkBackBrush}"
        d:LayoutOverrides="GridBox"
        Grid.Row="1">

    <Microsoft_Phone_Controls_Maps:MapItemsControl x:Name="ResultsList"
        ItemTemplate="{StaticResource MapPinPhoneBookDataTemplate}"
        ItemsSource="{Binding SearchResult.Results}" />
</Microsoft_Phone_Controls_Maps:Map>

Next up is the Imagery service and this completes the lap of the WP7C Bing Wrappers.

Enjoy!

WP7Contrib – Bing Service Wrapper Part II – Route

In the previous post we looked at the Location Service and how you can use the WP7C REST API Wrapper to make your app location aware. We also looked in some detail about the structure of the sample app for bing maps covering off how we use funq and to setup the scaffolding in the bootstrapper. Location is a simple but effective way of introducting geo location experiences into your app. Routes add an extra dimension to your app. If you have used this REST API then you will know that it’s not as simple as it should be.

For a deep dive into how the location bits work under the covers checkout Ollie’s post.

What we’ve done is to simplify this process so the WP7C is doing all the heavy lifting for you, making it a trivial task to incorporate these experiences into you app. In this post I want to cover off the Route Service. As with the other API’s provided by Bing this service provides the caller with the ability to :-

  • Calculate a Route – directions for walking, driving or transit routes are supported between waypoints.
  • Calculate Routes from Major Roads – driving routes using major roads to landmarks.

As you can see there are a number of supported actions the service can perform depending on your requirements. They all provide you with the ability to create a request that can be passed to the endpoint which intern calculates a route and returns a collection of points and directions. However, these API’s and what they do IMHO are not very well documented, the start here and finish there is trivial however the major roads and major routes and how to use these is not clear at times, also the objects returned from certain requests are complex. (If you are a Bing REST API person it would be great to hear from you so that we can gain a better understanding)

Obviously this has influenced the current implementation of the wrapper for getting Route information. Our objective as with Location was to simplify how you wire these components in to your application. Therefore the WP7C abstracts the different data types that are supported by the Bing Route service by wrapping all the supported types into super types that the WP7C can process.

So, from a UI prospective in terms of what you can bind to from Xaml there are 3 types that you need to know about :-

  • Landmark
  • GeoCoordinate
  • Address

As with the location service we use the CriterionFactory to help with the construction of the request. As mentioned above the Bing Route service supports 2 mechanisms; Calculate a Route; and Calculate Routes from Major Roads. The code below is taken from the Routes VM found in the Bing sample and illustrates how you can wire the calls into your app.

Calculate a Route using Landmarks

var waypoints = new List<WayPoint> 
{ 
      new WayPoint { Landmark = this.startLandmark }, 
      new WayPoint { Landmark = this.finishLandmark } 
};

this.SearchForRouteByLandmarks(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate a Route using an Address

var waypoints = new List<WayPoint>
{
      new WayPoint { Address = this.startAddress },
      new WayPoint { Address = this.finishAddress }
};

this.SearchForRouteByAddresses(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate a Route using an Points

var waypoints = new List<WayPoint>
{
      new WayPoint { Point = this.startPoint },
      new WayPoint { Point = this.finishPoint }
};

this.SearchForRouteByPoints(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate Routes from Major Roads

var routeDestination = new RouteDestination
{
      Landmark = this.majorRoads 
};

this.SearchForRouteFromMajorRoads(
      CriterionFactory.CreateRouteSearchFromMajorRoads(
            routeDestination, DistanceUnit.Kilometer));

 

The above methods wrap up the Rx calls that will do the request as I wanted to illustrate not only how simple you can make it but also that we wrap all of the above 3 concrete types into another type called WayPoint for all of the different permutations of the calls you have a consistent pattern

            CriterionFactory.CreateRouteSearch(waypoints)

Now that we have covered the supported types and the CriterionFactory we can put all this together and look at how we use Rx to make the async calls.

Setup the Request (the code below is for calcualting a route by using landmarks)

private void SearchForRouteByLandmarks(IRouteSearchCriterion criterion)
{
    DispatcherHelper.CheckBeginInvokeOnUI(
        () => { this.LandmarkStatus = "Calculating..."; });

    this.bingMapService.CalculateARoute(criterion)
        .ObserveOnDispatcher()
        .Subscribe(this.ProcessBingRouteSearchResponse,
                   FailedSearch,
                   () => 
                   { 
                     this.LandmarkStatus = 
                     "Completed, scroll left or right to see Directions &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; Maps..."; 
                   });
}

 

Handle the Response, Successful

private void ProcessBingRouteSearchResponse(RouteSearchResult result)
{
     if (result == null)
     {
          return;
     }

      this.SearchResult = result;
      if (this.SearchResult.Points.Count != 0)
      {
           this.CurrentMapSearchCenterPoint = this.SearchResult.Points[0];
           this.ItineraryItems = this.SearchResult.RouteLegs.SelectMany(leg => leg.ItineraryItems).ToList();
      }
}

Handle the Response, Fail

private static void FailedSearch(Exception exn)
{
      MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message),
                                    "Route Search",
                                    MessageBoxButton.OK);
}

 

We need to now pay some attention to the result object that comes back, which is the same for both service calls but they are processed differently. The Calculate a route response has a single object with some properties that are useful.

Distance information

<TextBlock Text="Distance Units:" />
<TextBlock Text="{Binding SearchResult.DistanceUnit}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1" />
<TextBlock Text="Duration Units:"
            Grid.Row="1" />
<TextBlock Text="{Binding SearchResult.DurationUnit}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="1" />
<TextBlock Text="Travel Distance:"
            Grid.Row="2" />
<TextBlock Text="{Binding SearchResult.TravelDistance}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="2" />
<TextBlock Text="Travel Duration:"
            Grid.Row="3" />
<TextBlock Text="{Binding SearchResult.TravelDuration}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="3" />

 

Directions for the route

<ListBox Grid.Row="2"
        BorderThickness="3"
        BorderBrush="White"
        Padding="5,5,5,5"
        ItemsSource="{Binding SearchResult.RouteLegs}"
        ItemTemplate="{StaticResource RouteLegsDataTemplate}"
        ScrollViewer.VerticalScrollBarVisibility="Visible" />
[sourcecode='xml']

The map

[sourcecode='xml']
<Microsoft_Phone_Controls_Maps:Map x:Name="searchresultsnearbymap"
                         ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
                         Center="{Binding CurrentMapSearchCenterPoint, Mode=TwoWay}"
                         ZoomBarVisibility="Collapsed"
                         CopyrightVisibility="Visible"
                         AnimationLevel="UserInput"
                         HorizontalContentAlignment="Stretch"
                         VerticalContentAlignment="Stretch"
                         Grid.RowSpan="2"
                         Background="{StaticResource SemiOpaqueDarkBackBrush}">

    <!--Need to add a map pin to show what your current position is on the map-->
    <Microsoft_Phone_Controls_Maps:MapPolyline Stroke="Green"
                         Locations="{Binding SearchResult.Points}"
                         StrokeThickness="6"
                         Opacity="0.7" />

    <Microsoft_Phone_Controls_Maps:MapItemsControl x:Name="ResultsList"
                         ItemTemplate="{StaticResource MapPinDataTemplate}"
                         ItemsSource="{Binding ItineraryItems}" />
</Microsoft_Phone_Controls_Maps:Map>

 

That now completes the loop, we are done! I hope that you will agree this is far simpler, more performant and highly reuseable way of incorporating a rich geo location style experience into you apps, when compared to the wsdl implementation.

The Major Roads implementation is the same pattern however we need to call the methods specific to this request type both on the Criterion Factory and on the Bing Map Service.

The Major Roads implementation seems to be using some sort of fuzzy logic with regards to what you can request. Which is very funky.
The description on MSDN

In some cases, you may prefer generating a route from a major intersection to a target destination, rather than generating a true point to point route. For example, most major landmark websites show directions “coming from the North” or “coming from the West”.

For example, the major road service supports a request like calculate the driving route to the Space Needle in Seattle and the service will return the directions. Cool!

In summary, the steps required to use the Route Service are :-

1. Create the type of request you want to make; Landmark, Address or Point.
2. Create a list of waypoints using the type declared in step 1.
3. Use the Criterion Factory to create a Route Search based on the waypoints you pass in.
4. Call the Bing Map Service method Calculate a Route and pass in the Route Search Criterion generated by the factory
5. Handle the Search Result object returned by the Bing Map Service.
6. Data bind the Search Result properties to Xaml Map control.

In the next post we can take a look at the imagery service.

Enjoy!

WP7 Contrib – Bing Service Wrapper Part I – Location

This being the first post about the Wrappers I thought that we should break the ice with the most commonly used service. Location. Out of all of the services this is the simplest to call but also we would suspect the most widely used. When you combine this service with the device location based WP7C bits then you can build your geo location aware app and have it plotting to a map and moving in real-time, or you could be helping your user to find the location of an address.

In the sample for using the location service we tackle both of these scenarios.

So, I am going to jump straight in here and assume that you have either looked at the sample in the Spikes folder of the WP7 Contrib (WP7C) or you have some experience of using the Rest API provided by the Bing Maps endpoint. If you have not done this then I would suggest opening up the sample and taking a quick look at the Location View Model, its pretty straight forwards so you should be back in 10.

First off if you have not already created a project then you need too. If you are using MVVM and some sort of DI library cool, if not no worries. There are two different options provided by the Location Service from the Bing REST API; you can either use the Geo Coordinate Location of the device and pass this to the service in order to give you back a current address; or you can enter a location to find out what Geo Coordinate Location is.

If you are not already using the WP7C components in you app (shame on you J) then you need to add a couple of references in order to get this up and running, these include:-

  • WP7Contrib.Services
    • BingMaps
    • BingMaps.Model
    • Location

These are the basic bits that you need to get your geo location app up and running. Once we have included those assemblies then we need to define the interfaces we want to use and the data objects that correspond to the location service calls.

First up we need to declare the private fields so let’s go ahead and do that

private readonly IBingMapService bingMapService;
private readonly ILocationService locationService;
private LocationRect boundingRectangle;
private GeoCoordinate currentDeviceGeoCoordinate;
private IDisposable currentLocationObserver;
private RelayCommand selectFindMyCurrentLocationCommand;
private RelayCommand selectFindGeoLocationFromAddressCommand;
private Address address;
private LocationData locationDataByPoint;

 

Next, we need to create a constructor for our VM. You will notice that not only am I using the ILocationService which is the WP7C’s Rx location component but we are also going to pass in a IBingMapService which is our wrapper that we will use to call the REST services. The other interfaces that I am using here are the navigation service and the logging component from WP7C.

public LocationViewModel(
INavigationService navigationService,
ILocationService locationService,
IBingMapService bingMapService,
ILog log)
: base(navigationService, log)
{
this.locationService = locationService;
this.bingMapService = bingMapService;
this.address = new Address {CountryRegion = "UK", PostalCode = "LE17 5ER"};
}

 

Currently, and this is consistent across all of our samples we are using Funq as our DI framework of choice, its light and simple which is why it’s great for WP7, we are not bound to Funq in anyway so if you want to use your Favourite DI then you can do so.

With our constructor defined we need to go ahead and do our register and resolve in the bootstrapper.

There is quite a bit of stuff happening in the bootstrapper, mainly because of the fact that we are taking advantage of the different components inside of the WP7C, now you don’t have to use these however if you need things like logging; want to store data; and if you have a design where you are not loading all the VM’s upfront take a look at the Last Message Replay. As this is the first in a series of posts we can deconstruct what is happening here in the future articles I will only reference this section.

The code below setups the Logging bits for us.

this.Container.Register<ILogManager>(c => new LoggingService("BingMaps"));
this.Container.Register<ILog>(c => this.Container.Resolve<ILogManager>());
<p>var logManager = this.Container.Resolve<ILogManager>();
logManager.Enable();

 

Here we setup the settings for the app and assign the key that we want to use for bing maps. The registered key in the code is registered to the WP7C so I would advise that you register, it does not take long and the key is generated instantly.

this.Container.Register<IStoreSettings>(c => new SettingsStore(this.Container.Resolve<ILog>()));
this.Container.Register<ISettings>(c => new Settings("Bing Key"));
var serialisationAssemblies = new List<Assembly> { this.GetType().Assembly };

 

Setup the cache provider and initialise it.

this.Container.Register<ICacheProvider>(c => new  IsolatedStorageCacheProvider("BingMaps", serialisationAssemblies,  c.Resolve<ILog>()));
var cache = this.Container.Resolve<ICacheProvider>();
System.Threading.ThreadPool.QueueUserWorkItem(state => cache.PreemptiveInitialise());

 

Setup the last replay messenger.

this.Container.Register<IMessenger>(c => new LastMessageReplayMessenger());

 

Setup the WP7C Navigation Service.

this.Container.Register<INavigationService>(

c => new ApplicationFrameNavigationService(((App)Application.Current).RootFrame));

 

Setup the WP7C Network service

this.Container.Register<INetworkService>(c => new NetworkMonitor(5000));

 

Setup the WP7C Storage service.

var assemblies = new List<Assembly> { this.GetType().Assembly, typeof(BaseModel).Assembly };
this.Container.Register<IStorageService>(c => new StorageService(assemblies, c.Resolve<ILog>()));

 

As we are using the Resource Client from WP7C we also need to add this setup code into our bootstrapper.

this.Container.Register<IEncodeProperties>(c => new UrlEncoder());
this.Container.Register<IHandleResourcesFactory>(c => new ResourceClientFactory(c.Resolve<ILog>()));

 

The final part is that we need to wire in the IBingMapService which needs to be resolved using some of the interfaces that we registered earlier.

this.Container.Register<IBingMapService>(c => new BingMapService(
c.Resolve<IHandleResourcesFactory>(),
c.Resolve<IEncodeProperties>(),
c.Resolve<ICacheProvider>(),
c.Resolve<ISettings>(),
c.Resolve<ILog>()));

 

Ok, so we nearly have, all of the underlying plumbing done what we need to do next is to setup the VM locator. If you need more details on this please refer to the sample code. Once you have the VM locator updated we can go ahead and bind our Data Context up to the VM using the service locator pattern in Xaml.

As I mentioned at the start of this article, the UI’s are more about form and function, so our intentions are purely to visualise all the different types of data coming back from the service. So, for this we went with simple UI controls to make sure that the data being returned from our request is correct.

Now, that we have the plumbing in place, and some simple UI that displays the responses, our next step is to make our requests out to the Bing Services. This code is going to live in the VM.

The first thing on our list to implement is that we need to make our app location aware, everything you need to do this is already baked in the WP7C, it just requires a simple bit of Rx to get it wired in. In order to do this we need to leverage the ILocation Service that we injected into the VM as this will find out what our current location is.

private GeoCoordinate currentDeviceGeoCoordinate;
private IDisposable currentLocationObserver;
private void ExecuteSelectFindMyCurrentLocationCommand()
{
try
{
this.currentLocationObserver =
this.locationService.Location()
.ObserveOnDispatcher()
.Subscribe(geoCoordinate =>
{
this.CurrentDeviceGeoCoordinate = geoCoordinate;
this.SearchForLocation(this.BuildLocationSearchForPoint());
});
}
catch (Exception exn)
{
MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message), "Location Search",                MessageBoxButton.OK);
}}

 

Notice in the subscribe how we are assigning a value to the VM’s Current Device Geo Coordinate Property which is bound up in the view; also note that we are then doing a Search for a geo location and passing into this method the result from the Build Location Search For Point. We decided that in order for us to wrap up all the services and provide a common API from which users can use the services we would adopt a factory style pattern. So, what’s going on in the Build method? Well here we are calling out to the factory and asking it to create what we need in order to query the Bing services for dealing with the request.

private ILocationSearchPointCriterion BuildLocationSearchForPoint()
{
return CriterionFactory.CreateLocationSearchForPoint(this.CurrentDeviceGeoCoordinate);
}

 

And that is all you need to add location awareness to your app, I hope that you agree with me that this is rather straight forwards. Next up we need to build out the search for location method, which is going to use the Bing wrapper service from the WP7C to search for a location. If you have looked over the code you will see that we have 2 overloaded methods, one which deals with Geo Location and the other which deals with addresses.

private void SearchForLocation(ILocationSearchPointCriterion criterion)
{
this.bingMapService.SearchForLocationUsingPoint(criterion)
.ObserveOnDispatcher()
.Subscribe(this.ProcessSearchLocationByPointResponse,
FailedSearch,
CompletedSearch);
}

 

And for completeness I have included the code for the address mechanism below.

 

private void SearchForLocation(ILocationSearchAddressCriterion criterion)
{
this.bingMapService.SearchForLocationUsingAddress(criterion)
.ObserveOnDispatcher()
.Subscribe(this.ProcessSearchLocationByAddressResponse,
FailedSearch,
CompletedSearch);
}

 

Note that there are a couple of differences between the overloads; first the interface type that we are passing into our method for locations we always need to use the ILocationSearchPointCriterion and for addresses we need to use the ILocationSearchAddressCriterion; and the other difference is that we use a different method to deal with the response that we get sent from the Bing Services.

private void ProcessSearchLocationByPointResponse(LocationSearchResult result)
{
if (result == null)
{
return;
}
if (result.Locations.Count != 0)
this.LocationDataByPoint = result.Locations[0];
}

In order to successfully process the data and then work on this data the WP7C provides you with the data transformation classes that you need and does all the map and wrap code so that you don’t have to. In the code above this is illustrated by our use of the LocationDataByPoint property which uses the Location Data class from the WP7C, we are using databinding in the view and wiring up to this property from the VM .

So, just to recap what we have covered are a couple of things here; first we made our app Geo Location aware by using the WP7C Rx location service; which was then wired up to the Bing Services Wrapper and we used this to provide an address of the device’s current location; and for completeness we provide a way for the user to enter details of an address and the app responds with a Geo Location that corresponds to the address.

Admittedly we are doing some simple tasks here however its super important that we put in the ground work so that you can gain a deep understanding of how the wrappers work. We would really like to hear your feedback, if you have built an app using the Bing services we would also be interested in talking to you about your sceanrios.

In the next post I will dig into using the Route Service.

Ollie has some deep dive blog posts planned which are based around the patterns that he is using along with some gems of information around using Rx with these more traditional patterns so watch out for those.

Enjoy!