Monday, April 30, 2012

LocationServices for Windows Phone, part 5: exploring surrounding POI's from Nokia Places

before we begin

Get the API keys set up – if you haven’t registered already, go to http://api.maps.nokia.com/en/restplaces/overview.html and do so, then register for a personal app key & code that you can use. After that’s done, edit the App.xaml and insert your own keys.

        <usoniandream:ServiceURI x:Key="NOKIA_SERVICE_URI_PLACES" URL="http://places.nlp.nokia.com/places/v1/" />

        <usoniandream:ServiceAPIKey x:Key="NOKIA_APP_CODE" Value="" />
        <usoniandream:ServiceAPIKey x:Key="NOKIA_APP_ID" Value="" />

the namespace you’ll need to add to your App.xaml is:

            xmlns:usoniandream="clr-namespace:Usoniandream.WindowsPhone.LocationServices.Models;assembly=Usoniandream.WindowsPhone.LocationServices"

NuGet for the prerequisites

Easiest way to grab both the Reactive Extensions (rx) and RestSharp is to use NuGet. Install the following two packages and you’re set to move forward:

  • Rx_Experimental-Xaml version 1.1.11111
  • RestSharp version 102.7

add the references needed

1) Add references to the core library:

  • Usoniandream.WindowsPhone.LocationsServices
  • Usoniandream.WindowsPhone.Extensions
  • Usoniandream.WindowsPhone.GeoConverter

2) Add a reference to the Bing data library:

  • Usoniandream.WindowsPhone.LocationsServices.Nokia

add some code

3) Declare a service layer:

        public LocationServices.Service.Nokia.Reactive.ServiceLayer nokiaservicelayer = new LocationServices.Service.Nokia.Reactive.ServiceLayer();

4) Declare a property container for the results:

        public ObservableCollection<Place> NokiaPlaces { get; set; }

5) Wire the call to get the POI’s nearby:

            var places = nokiaservicelayer.GetNokiaPlaces(new WindowsPhone.LocationServices.SearchCriterias.Nokia.Places.Places(CurrentLocation, "sv, en-gb;q=0.8, en;q=0.7"))
                .DistinctUntilChanged()
                .ObserveOnDispatcher()
                .Subscribe(x =>
                    {
                        NokiaPlaces.Add(x);
                    },
                    ex =>
                    {
                        // handle error..
                    });

6) Finally, a bit of xaml to wrap it all up:

                    <toolkit:MultiselectList x:Name="mslNokiaPlaces" ItemsSource="{Binding NokiaPlaces}" Margin="-20,0,0,0" Visibility="{Binding NokiaPlaces.Count, Converter={StaticResource NumberToVisibilityConverter}}">
                        <toolkit:MultiselectList.ItemTemplate>
                            <DataTemplate>
                                <Button Style="{StaticResource ChromelessButton}" DataContext="{Binding .}">
                                    <StackPanel>
                                        <TextBlock x:Name="Title" Foreground="#004C9A" Text="{Binding Content}"  TextTrimming="WordEllipsis" Style="{StaticResource PhoneTextLargeStyle}" />
                                            <TextBlock Text="sponsored result" Style="{StaticResource PhoneTextSubtleStyle}" Visibility="{Binding Sponsored, Converter={StaticResource BoolToVisibilityConverter}}"/>
                                        <TextBlock Text="{Binding Distance, Converter={StaticResource DoubleToDistanceConverter}}" Style="{StaticResource PhoneTextNormalStyle}" />
                                    </StackPanel>
                                </Button>
                            </DataTemplate>
                        </toolkit:MultiselectList.ItemTemplate>
                        <toolkit:MultiselectList.ItemContainerStyle>
                            <Style TargetType="toolkit:MultiselectItem">
                                <Setter Property="Margin" Value="-12,0" />
                                <Setter Property="CacheMode" Value="BitmapCache" />
                            </Style>
                        </toolkit:MultiselectList.ItemContainerStyle>
                    </toolkit:MultiselectList>

7) And the end result gives us:

image

8) from there you can easily add a click handler to the surrounding button that goes out to fetch the details in a similar way as shown below:

        public PlaceDetails NokiaPlaceDetails { get; set; }

        public void FetchDetails(LocationServices.Models.Nokia.Places.Place item)
        {
            NokiaService.GetNokiaPlace(new LocationServices.SearchCriterias.Nokia.Places.Place(item.Id, "sv, en-gb;q=0.8, en;q=0.7"))
            .ObserveOnDispatcher()
            .Subscribe(x =>
            {
                NokiaPlaceDetails = x;
            },
                ex =>
                {
                    // handle errors..
                },
                () =>
                {
                    this.RaisePropertyChanged("");
                });
        }

9) and the end result of that place detail query could look something like this after you’ve hammered it into a xaml view:

image

9) and finally, if you instead want to display your results on a map it’s as easy as binding the collection to a MapItemsControl:

    <maps:Map ZoomBarVisibility="Visible" ScaleVisibility="Visible" ZoomLevel="15" Center="{Binding CurrentLocation}" CredentialsProvider="{StaticResource BingCredentials}">
    <maps:MapItemsControl ItemsSource="{Binding NokiaPlaces}">
        <maps:MapItemsControl.ItemTemplate>
        <DataTemplate>
            <maps:Pushpin Background="#004C9A" Content="{Binding Content}" Location="{Binding Location}" />
        </DataTemplate>
        </maps:MapItemsControl.ItemTemplate>
    </maps:MapItemsControl>
    <maps:Pushpin Location="{Binding CurrentLocation}" Style="{StaticResource MyLocationStyle}" />
    </maps:Map>

The BingCredentials is your Bing API key that the Maps control require in order to not show the “invalid credentials” and the MyLocationStyle is simply a style for the pushpin in the shape of an ellipsis.

10) with the neat result as seen below:

image

The framework libraries, source code and sample app are all on GitHub: https://github.com/peterdrougge/Usoniandream.WIndowsPhone.LocationServices

No comments: