Friday, May 18, 2012

LocationServices for Windows Phone: Bing Translation made simple

Hello again. To be honest, a translation API is not in any way a location-aware API (unless you can send in coordinates and get the target language), but it is a tremendously useful API none the less and a lot of solutions could benefit from having one.

For that reason I’ve implemented Bing Translation in the LocationServices for Windows Phone framework.

Usage is exactly like the rest of the framework: you specify a criteria (in this case a Translation criteria) and then you fire that at the service and out you get an observable Translation (or a collection of that, depending on how you use it).

translation

In the screenshot above I’ve sent the Swedish words “badplatser”, “lekpark”, “samhälle”, “polis” & “källkod” for translation to it’s English equivalent.

The implementation is created in such a way that you can add several words (or phrases for that matter) to the criteria and it will only fire one shot at the service, instead of one per word/phrase.

Enough talk, let’s code.

References

These are the bare minimum references needed.

  • RestSharp
    • local build of RestSharp 103.1 with a tiny change. Located in the lib folder.
  • Reactive Extensions
    • NuGet: Rx_Experimental-Xaml
  • LocationServices for WIndows Phone
    • Usoniandream.WindowsPhone.LocationServices
    • Usoniandream.WindowsPhone.LocationServices.Bing

ViewModel code

in short: an ObservableCollection for the result, a ServiceLayer and a method that wires the translation.

    public class MainViewModel : ViewModelBase
    {
        private ObservableCollection<Usoniandream.WindowsPhone.LocationServices.Models.Bing.Translation> translations;
        public ObservableCollection<Usoniandream.WindowsPhone.LocationServices.Models.Bing.Translation> Translations
        {
            get
            {
                if (translations == null)
                    translations = new ObservableCollection<Usoniandream.WindowsPhone.LocationServices.Models.Bing.Translation>();
                return translations;
            }
            set
            {
                translations = value;
            }
        }

        public Usoniandream.WindowsPhone.LocationServices.Service.Bing.Reactive.ServiceLayer serviceLayer { get; set; }

        public MainViewModel()
        {
            serviceLayer = new Usoniandream.WindowsPhone.LocationServices.Service.Bing.Reactive.ServiceLayer();
        }

        public void WireBingTranslation()
        {
            IsDataLoading = true;
            Usoniandream.WindowsPhone.LocationServices.SearchCriterias.Bing.Translation criteria = new Usoniandream.WindowsPhone.LocationServices.SearchCriterias.Bing.Translation("sv", "en", "en-US", "badplatser", "lekpark", "samhälle", "polis", "källkod");
            var rxbing = serviceLayer.Translate(criteria)
                .ObserveOnDispatcher()
                .Finally(() =>
                {
                    IsDataLoading = false;
                })
                .Subscribe(
                // result
                    x =>
                    {
                        Translations.Add(x);
                    },
                // exception
                    ex =>
                    {
                        MessageBox.Show(ex.Message);
                    });
        }
        public bool IsDataLoading { get; set; }
    }

XAML code

I’ve left out everything from the view except this tiny ListBox implementation ‘cause it really is the only interesting part.

            <ListBox ItemsSource="{Binding Translations}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Margin="12,0" Text="{Binding From}" Style="{StaticResource PhoneTextNormalStyle}" />
                            <TextBlock Margin="12,0" Text="translates to" Style="{StaticResource PhoneTextSubtleStyle}" />
                            <TextBlock Margin="12,0,12,24" Text="{Binding To}" Style="{StaticResource PhoneTextNormalStyle}" />
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

And, as shown above, that gives us:

translation

Wrapping up

That sample code is available here for download, just remember that you need a Bing AppID of your own and set that in the App.xaml. If you don't already have an AppID, you can sign up and get it at http://www.bing.com/developers/appids.aspx.

Now, for anyone using the other parts of the framework you also have the option of sending any model that implements ILocation in the criteria instead of strings. Doing so will translate the Content property of that object. In a future version you’ll get the sent in object back translated, but for now you’ll just have to do with the content as a Translation.

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

Tuesday, May 15, 2012

LocationServices for Windows Phone: now with caching support!

I’ve added a simple caching container for the framework, enabling you to cache the results from a criteria.

Simply set the CacheProvider property on the service to a cache provider that implements ICacheProvider from the framework, then configure the caching in the CacheSettings property of the criteria.

Consider the following Instagram criteria search:

        public Service.Instagram.Reactive.ServiceLayer instagramservicelayer { get; private set; }

        public MainViewModel()
        {
            this.instagramservicelayer = new Service.Instagram.Reactive.ServiceLayer();
        }

        private void WireInstagramPivotItem()
        {
            IsDataLoading = true;
            GenericPivotItem instagram = new GenericPivotItem() { Header = "photos", Source = "instagram" };
            SearchCriterias.Instagram.MediaByLocation criteria = new SearchCriterias.Instagram.MediaByLocation(new GeoCoordinate(40.74917, -73.98529));
            
            var rxinstagram = instagramservicelayer.GetMediaByLocation(criteria)
                .Take(20)
                .ObserveOnDispatcher()
                .Finally(() =>
                {
                    PivotItems.Add(instagram);
                    IsDataLoading = false;
                })
                .Subscribe(
                // result
                    x =>
                    {
                        instagram.Items.Add(x);
                    },
                // exception
                    ex =>
                    {
                        MessageBox.Show(ex.Message);
                    });
        }

Now, to add caching to that you simply add a provider to the service and specify caching on the criteria:

        public MainViewModel()
        {
            this.instagramservicelayer = new Service.Instagram.Reactive.ServiceLayer() 
            { 
                CacheProvider = new LocationServices.Caching.IsoStoreCache.IsolatedStorageCacheProvider() 
            };
        }

        public Service.Instagram.Reactive.ServiceLayer instagramservicelayer { get; private set; }

        private void WireInstagramPivotItem()
        {
            IsDataLoading = true;
            GenericPivotItem instagram = new GenericPivotItem() { Header = "photos", Source = "instagram" };
            SearchCriterias.Instagram.MediaByLocation criteria = new SearchCriterias.Instagram.MediaByLocation(new GeoCoordinate(40.74917, -73.98529))
                {
                    CacheSettings = new SearchCriterias.CriteriaCacheSettings(60 * 60 * 24)
                };
 
            var rxinstagram = instagramservicelayer.GetMediaByLocation(criteria)
                .Take(20)
                .ObserveOnDispatcher()
                .Finally(() =>
                {
                    PivotItems.Add(instagram);
                    IsDataLoading = false;
                })
                .Subscribe(
                // result
                    x =>
                    {
                        instagram.Items.Add(x);
                    },
                // exception
                    ex =>
                    {
                        MessageBox.Show(ex.Message);
                    });

        }

In the code above the cache duration (specified in the CacheSettings) is the number of seconds the cached item(s) should be considered valid, here 60*60*24 = 24 hours.

You can of course create your own cache provider - simply implement the ICacheProvider interface and it’s methods in your own provider class. You’ll find the interface in the Caching namespace in the Usoniandream.WindowsPhone.LocationServices library.

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

Sunday, May 13, 2012

Introducing Stockholm Explorer for Windows Phone

This post will be a bit weird, it’s written in English but it’s actually all about a Swedish app I’ve just published.

As of today Stockholm Explorer for Windows Phone is available on the marketplace: http://www.windowsphone.com/sv-SE/apps/270e2242-e160-4f05-b70e-b216705349e9

This app is a POI (Point Of Interest) finder/explorer for the city of Stockholm and it’s surroundings - built entirely using the LocationServices for Windows Phone framework.

PeterDrougge_None_FX_2012-05-05_09-56-46

The app utilizes the framework to combine and present data from Stockholm, Nokia Places, Twitter, FLickr, Commute Greener and Instagram. And it does so brilliantly ;)

If you’re Swedish (sorry – at the moment the app is in Swedish only, this however I’m planning on changing in the next version) and either living in Stockholm or happen to be/going there I hope you’ll find it useful.

The app has been developed using frameworks such as Reactive Extensions, RestSharp, Silverlight for Windows Phone Toolkit and LocationServices for Windows Phone.

Download: http://www.windowsphone.com/sv-SE/apps/270e2242-e160-4f05-b70e-b216705349e9

Thursday, May 10, 2012

LocationServices for Windows Phone: getting media from Instagram based on location

Just a few minutes ago I pushed updates to the Instagram part of the framework, here’s a quick example of getting media based on a location:

        public MainViewModel()
        {
            this.instagramservicelayer = new Service.Instagram.Reactive.ServiceLayer();
        }

        private ObservableCollection<GenericPivotItem> pivotItems;
        public ObservableCollection<GenericPivotItem> PivotItems { get { if (pivotItems == null) pivotItems = new ObservableCollection<GenericPivotItem>(); return pivotItems; } set { pivotItems = value; } }

        public Service.Instagram.Reactive.ServiceLayer instagramservicelayer { get; private set; }

        private void WireInstagramPivotItem()
        {
            IsDataLoading = true;
            GenericPivotItem instagram = new GenericPivotItem() { Header = "photos", Source = "instagram" };
            var rxinstagram = instagramservicelayer.GetMediaByLocation(new Usoniandream.WindowsPhone.LocationServices.SearchCriterias.Instagram.MediaByLocation(new GeoCoordinate(40.74917, -73.98529)))
                .Take(20)
                .ObserveOnDispatcher()
                .Finally(() =>
                {
                    PivotItems.Add(instagram);
                    IsDataLoading = false;
                })
                .Subscribe(
                // result
                    x =>
                    {
                        instagram.Items.Add(x);
                    },
                // exception
                    ex =>
                    {
                        MessageBox.Show(ex.Message);
                    });

        }

with the result as seen below (don’t pay attention to the lack of design):

instagram

NOTE: the project currenty holds a local version of the RestSharp dll located in the lib folder. This is due to the fact that the JsonDeserializer in RestSharp was throwing InvalidCastExceptions when parsing certain types of json result. I’ve updated the JsonDeserializer in this local version.

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

LocationServices for Windows Phone: Added Google Places and Instagram

Last night I added data libraries for Google Places and Instagram.

SearchCriterias available for Google Places:

  • PlacesByRadius
  • PlaceDetails
  • EventDetails

SearchCriterias available for Instagram:

  • PlacesByLocation
  • MediaByLocation
  • MediaDetails

At the moment they won’t fly since the mappers for each library is not completed – something I’m going to push very shortly and then they’re ready to use.

Windows Phone development: RestSharp and JSON response without a root object

Not everyone thinks alike, and not everyone builds the same.

RestSharp is, in lack of better words, freakin’ awesome. It rocks when it comes to Windows Phone web requests. There’s one little thing you should look out for though, and that’s the structure of the JSON response.

Basically, there’s two types: the root response type where the response has a root object that holds the response, and the rootless response type where the response lacks a root object and instead returns a collection of items at this point.

Parsing the first one is a piece of cake with RestSharp, all you have to do is something like

            RestSharp.IRestClient client = new RestSharp.RestClient("http://MyBaseUrlThatIsNotRealButOnlyAnExample.com");
            RestSharp.IRestRequest request = new RestSharp.RestRequest("MyResource/Example/IsAlso/NotReal");

            var asyncHandle = client.ExecuteAsync<MySampleObject>(request, response =>
            {
                // got the response..
            });

and you’re set. It automagically deserializes the json response to your model.

But.. (there’s always that “but”). If the object is rootless you might need to append a little extra at the beginning and end of the response prior to it being deserialized.

In this case all you have to do is make use of the OnBeforeDeserialization handler of the Request object.

            RestSharp.IRestClient client = new RestSharp.RestClient("http://MyBaseUrlThatIsNotRealButOnlyAnExample.com");
            RestSharp.IRestRequest request = new RestSharp.RestRequest("MyResource/Example/IsAlso/NotReal");
            request.OnBeforeDeserialization = response => {response.Content = string.Format("{0}{1}{2}", prefix, response.Content, suffix)};

            var asyncHandle = client.ExecuteAsync<MySampleObject>(request, response =>
            {
                // got the response..
            });

where “prefix” and “suffix” in the above code is the wrapper you need to make a root object surrounding the original response.

You can place it as a method instead if you want:

        private void AddPaddingToResponse(IRestResponse response)
        {
            response.Content = string.Format("{0}{1}{2}", "{\"features\":", response.Content, "}");

And use that for OnBeforeDeserialization (this is approach is more friendly for debugging purposes, the other is just a bit more cool and inline):

            RestSharp.IRestClient client = new RestSharp.RestClient("http://MyBaseUrlThatIsNotRealButOnlyAnExample.com");
            RestSharp.IRestRequest request = new RestSharp.RestRequest("MyResource/Example/IsAlso/NotReal");
            request.OnBeforeDeserialization = AddPaddingToResponse;

            var asyncHandle = client.ExecuteAsync<MySampleObject>(request, response =>
            {
                // got the response..
            });

And finally, a little sidenote: remember that you can Cancel the request if you want. Nice feature that helps with responsiveness of your app and is easily implemented by overriding the Back button event and simply calling:

            asyncHandle.Abort();

That’s it, and that’s that.

LocationServices for Windows Phone: drop it like it’s hot

As of today the dependency to JSON.NET is no longer required and therefore it has been removed. This was made possible by upgrading RestSharp to version 103.1.

There might be a few Json deserialization issues to take care of in the near future, but the majority of them should be fine since I’ve tested quite a lot of them already.

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

Monday, May 07, 2012

Windows Phone development: an alternative to zooming all your map locations into view

When you’re using the Maps control to layout your items it’s always nice if you give the user the possibility to zoom/scale to show all items, this however can be a pain. While I’ve seen a few different approaches to solving this, like diving deep into projection/delta and more I thought I’d share a different (and a lot easier) approach.

Often it’s sufficient enough to just create a LocationRect based on the current GeoCoordinates and add a little “padding” to it, then call the SetView method of the map with that LocationRect.

Here’s a sample:

image

in the image above we’re fairly zoomed down to a level where a lot of items are simply out of view. That helicopter button in the application bar does the following when clicked:

            // simple collection later used for the LocationRect..
            List<GeoCoordinate> coords = new List<GeoCoordinate>();

            // add current location (yeah, we wanna be in the picture as well)
            coords.Add(viewModel.CurrentLocation);
            
            // transform any location-aware item collections into simple GeoCoordinate lists, then add that to the coords list..
            if (this.mapServiceUnits.Visibility == System.Windows.Visibility.Visible)
                coords.AddRange(viewModel.ServiceUnits.Select<Usoniandream.WindowsPhone.LocationServices.Models.Stockholm.Base.IServiceUnit, GeoCoordinate>(x => x.Location));
            if (this.mapNokiaPlaces.Visibility == System.Windows.Visibility.Visible)
                coords.AddRange(viewModel.NokiaPlaces.Select<Usoniandream.WindowsPhone.LocationServices.Models.Nokia.Places.Place, GeoCoordinate>(x => x.Location));
            
            // finally, use the GetLocationRect with a little "padding" to nicely fit the items in view. (mapLocations is the name of the map control in this example)
            mapLocations.SetView(MapExtensions.GetLocationRect(coords, 0.003));

and that leaves us with a map zooming out nicely to show all the items:

image

How was that accomplished? Basically all you need is the GetLocationRect extension method included in the code below:

//
// Copyright (c) 2012 Peter Drougge
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using Microsoft.Phone.Controls.Maps;
using System.Device.Location;
using System.Collections.Generic;

namespace Usoniandream.WindowsPhone.Extensions
{
    public static class MapExtensions
    {
        public static LocationRect GetLocationRect(IEnumerable<GeoCoordinate> coords, double padding)
        {
            LocationRect rect = LocationRect.CreateLocationRect(coords);
            if (padding>0)
            {
                rect.West -= padding;
                rect.East += padding;
                rect.North += padding;
                rect.South -= padding;
            }
            return rect;
        }
    }
}

now, just to clarify I’m gonna show those images next to each other so you’ll see the difference:

imageimage

It might not be the most elegant solution, nor the most mathematically correct, but if you just want to make sure your items (at least the actual locations of them) are in view, well then I’m confident that little piece of code will suffice.

Saturday, May 05, 2012

LocationServices for Windows Phone: example of an application using parts of the framework

My second wild creation is waiting certification approval at the moment, that however hasn’t stopped me from completing the next version of it: Stockholm Explorer v1.1.

The original v1.0 version combines POI information from the city of Stockholm and Nokia Places, giving easy access to addresses, phone numbers etc. But that’s about it. While waiting for the approval of it I decided to add some more functionality, and thus the addition of Twitter, Flickr & CommuteGreener to the framework.

In the new 1.1 version not only will you get information such as phone numbers, opening hours, addresses etc, but you’ll also get Flickr photos from the vicinity of the location, as well as nearby tweets and a Co2 emission calculation based on different forms of transport to reach the location.

Consider this screenshot a sneak preview of the next version of Stockholm Explorer for Windows Phone that will be available.. well.. soon after the 1.0 version is made available.

PeterDrougge_None_FX_2012-05-05_09-56-46

LocationServices framework parts used:

  • Usoniandream.WindowsPhone.LocationServices.Stockholm
  • Usoniandream.WindowsPhone.LocationServices.Nokia
  • Usoniandream.WindowsPhone.LocationServices.Twitter
  • Usoniandream.WindowsPhone.LocationServices.Flickr
  • Usoniandream.WindowsPhone.LocationServices.Commute

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

Thursday, May 03, 2012

Windows Phone development: Improving the startup time and responsiveness of your application

I’m sure you all know the certification rule of how long your app is allowed to load (if not, here’s a big tip: go read the certification requirements and guides – it’ll save you a lot of time later on). Now, assuming you’re familiar with that rule I won’t cover it any further, nor will I cover the how & why of the below, I’m just going to leave you with one more option to improve startup time instead of just transferring load to the Loaded event..

Here’s what you really should avoid

Fetching data in the constructor is never a good idea.

    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // here you really shouldn't be loading anything since the first frame hasn't fired yet, but let's assume that you did..
            ViewModel.RunMyDataFetchingStuff();
        }
    }

And here’s how you normally avoid the above

Deferring load to the Loaded event of the page let’s the app fire the first rendered frame.

    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            // transfer loading to only run after the first frame..
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // aaaaaand here we load some data..
            ViewModel.RunMyDataFetchingStuff(); 
        }
    }

If you still experience delays here’s an extension to the above alternative

If you think there’s still room for improvement when it comes to loading your views, try using a timer to further defer the load past the regular Loaded event.

    public partial class MainPage : PhoneApplicationPage
    {
        DispatcherTimer firstTimer = new DispatcherTimer();

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // hook up timer..
            firstTimer.Interval = TimeSpan.FromMilliseconds(500);
            firstTimer.Tick += new EventHandler(firstTimer_Tick);
            // transfer loading to only run after the first frame..
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // and off we go - tick, tick, tick, tick, boom!
            firstTimer.Start();
        }
        void firstTimer_Tick(object sender, EventArgs e)
        {
            firstTimer.Stop(); 
            // aaaaaand here we instead load some data, ‘cause here we really should be clear of any initial freeze..
            ViewModel.RunMyDataFetchingStuff(); 
        }
    }

Performance issues can be a pain for any developer to tackle, but also for the end user. Try to focus on the experience you initially set out to create, then attack each issue one at a time. There’s plenty of patterns, tutorials and guidance out there in case you need help. As a start you can look here, here, here, here or here.

Needless to say the above won’t act as a cleaver on your startup time, but it might help.

Windows Phone development–applying a custom style to change the visual presentation of a radiobutton

Fact: the Metro principles are great and the controls we have available renders with grace and simplicity.

Regardless of all that, there are times when we just want the functionality of a radiobutton list, but the appearance of something completely different. This is where retemplating or applying styles come into play and really makes xaml shine.

in the following example we’re going to turn this..

image

.. into this..

image

.. by simply applying a custom style.

so, from the top then, we have a group of radiobuttons..

    <RadioButton x:Name="rbCar" GroupName="one" IsChecked="True">
        Car
    </RadioButton>
    <RadioButton x:Name="rbBike" GroupName="one">
        Motorcycle
    </RadioButton>
    <RadioButton x:Name="rbTruck" GroupName="one">
        Truck
    </RadioButton>
    <RadioButton x:Name="rbWheelchair" GroupName="one">
        Wheelchair
    </RadioButton>

now, we’ll addew n a custom style called “AVeryDifferentRadioButton”..

        <Style x:Key="AVeryDifferentRadioButton" BasedOn="{StaticResource PhoneRadioButtonCheckBoxBase}" TargetType="RadioButton">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="RadioButton">
                        <Grid Background="Transparent">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver"/>
                                    <VisualState x:Name="Pressed" />
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentGrid">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="CheckStates">
                                    <VisualState x:Name="Checked">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentGrid">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unchecked">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ContentGrid">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneSubtleBrush}"/>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Indeterminate"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid x:Name="ContentGrid" Margin="{StaticResource PhoneTouchTargetLargeOverhang}" Width="80">
                                <ContentControl VerticalAlignment="Center" HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" 
                                                x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" 
                                                Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" 
                                                FontFamily="{TemplateBinding FontFamily}" Margin="0" Padding="{TemplateBinding Padding}" />
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

and we’ll use that style and also change the contents to images..

    <RadioButton x:Name="rbCar" GroupName="one" IsChecked="True">
        <Image Source="/Content/images/car.png" />
    </RadioButton>
    <RadioButton x:Name="rbBike" GroupName="one">
        <Image Source="/Content/images/bike.png" />
    </RadioButton>
    <RadioButton x:Name="rbTruck" GroupName="one">
        <Image Source="/Content/images/truck.png" />
    </RadioButton>
    <RadioButton x:Name="rbWheelchair" GroupName="one">
        <Image Source="/Content/images/wheelchairpng" />
    </RadioButton>

and that is it:

image

Now it renders in quite differently while still giving us the functionality of a traditional radiobutton.

LocationServices for Windows Phone update: added Twitter

I’ve added Twitter as a new data layer library with a search criteria to SearchByRadius. Using this search will return all tweets with a valid geo location (either by the Geo attribute, or by a string parse of the Location attribute) within the set radius from the specified location (GeoCoordinate).

twitter

Usage example

        public MainViewModel()
        {
            this.twitterrservicelayer = new Service.Twitter.Reactive.ServiceLayer();
        }
        private ObservableCollection<GenericPivotItem> pivotItems;
        public ObservableCollection<GenericPivotItem> PivotItems { get { if (pivotItems == null) pivotItems = new ObservableCollection<GenericPivotItem>(); return pivotItems; } set { pivotItems = value; } }
        public Service.Twitter.Reactive.ServiceLayer twitterrservicelayer { get; private set; }

        private void WireTwitterPivotItem()
        {
            IsDataLoading = true;
            GenericPivotItem tweets = new GenericPivotItem() { Header = "tweets", Source = "twitter" };

            var rxtweets = twitterrservicelayer.GetTweetsByRadius(new Usoniandream.WindowsPhone.LocationServices.SearchCriterias.Twitter.SearchByRadius(new GeoCoordinate(40.74917, -73.98529), 0.5))
           .Take(20)
           .ObserveOnDispatcher()
           .Finally(() =>
           {
               PivotItems.Add(tweets);
               IsDataLoading = false;
           })
           .Subscribe(
                // result
               x =>
               {
                   tweets.Items.Add(x);
               },
                // exception
               ex =>
               {
                   // handle exception..
               });
        }

Current framework contents (as of 2012-05-03)

Core libraries:

  • Usoniandream.WindowsPhone.Extensions
  • Usoniandream.WindowsPhone.GeoConverter
  • Usoniandream.WindowsPhone.LocationServices

Data libraries:

  • Usoniandream.WindowsPhone.LocationServices.Bing
  • Usoniandream.WindowsPhone.LocationServices.Commute
  • Usoniandream.WindowsPhone.LocationServices.Flickr 
  • Usoniandream.WindowsPhone.LocationServices.Goteborg
  • Usoniandream.WindowsPhone.LocationServices.Nokia
  • Usoniandream.WindowsPhone.LocationServices.Orebro 
  • Usoniandream.WindowsPhone.LocationServices.Stockholm
  • Usoniandream.WindowsPhone.LocationServices.Stockholm.AR
  • Usoniandream.WindowsPhone.LocationServices.Twitter

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

Wednesday, May 02, 2012

LocationServices for Windows Phone update: added Flickr

I’ve added Flickr as a new data layer library with search criterias for Search by location and Photo information.

flickr

Current framework contents (as of 2012-05-02)

Core libraries:

  • Usoniandream.WindowsPhone.Extensions
  • Usoniandream.WindowsPhone.GeoConverter
  • Usoniandream.WindowsPhone.LocationServices

Data libraries:

  • Usoniandream.WindowsPhone.LocationServices.Bing
  • Usoniandream.WindowsPhone.LocationServices.Commute
  • Usoniandream.WindowsPhone.LocationServices.Flickr 
  • Usoniandream.WindowsPhone.LocationServices.Goteborg
  • Usoniandream.WindowsPhone.LocationServices.Nokia
  • Usoniandream.WindowsPhone.LocationServices.Orebro 
  • Usoniandream.WindowsPhone.LocationServices.Stockholm
  • Usoniandream.WindowsPhone.LocationServices.Stockholm.AR

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

LocationServices for Windows Phone update: added CommuteGreener and Örebro data

Today has been a busy day, this is however the last post regarding updates for now.

Usoniandream.WindowsPhone.LocationServices.Commute

Get emission calculations based on start & end locations

Usoniandream.WindowsPhone.LocationServices.Orebro

Data from the city of Örebro. Current endpoints included are Parkings, Baths, Recycling stations, Parks, Libraries, Preschools & Recycling centrals. This will be updated later with more content.

örebro badplatserörebro parkerörebro parkeringarörebro återvinning

So, as of today the framework has grown a bit and will continute to do so whenever I find the time to add more content to it. If you want to you’re welcome to contribute – the entire source is available on GitHub.

Current framework contents (as of 2012-05-01)

Core libraries:

  • Usoniandream.WindowsPhone.Extensions
  • Usoniandream.WindowsPhone.GeoConverter
  • Usoniandream.WindowsPhone.LocationServices

Data libraries:

  • Usoniandream.WindowsPhone.LocationServices.Bing
  • Usoniandream.WindowsPhone.LocationServices.Commute
  • Usoniandream.WindowsPhone.LocationServices.Goteborg
  • Usoniandream.WindowsPhone.LocationServices.Nokia
  • Usoniandream.WindowsPhone.LocationServices.Orebro 
  • Usoniandream.WindowsPhone.LocationServices.Stockholm
  • Usoniandream.WindowsPhone.LocationServices.Stockholm.AR

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

Tuesday, May 01, 2012

LocationServices for Windows Phone, Göteborg update: Traffic cameras & Bike stations added

As of today the Goteborg data layer now also contain methods to fetch Traffic cameras and Bike stations by radius.

bike stationsgöteborg traffic cameras

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

Windows Phone Location-aware applications: a tip to help you keep track of yourself

handling location events in your application is in no way rocket science, in fact it’s about as easy as it can be.

I’m using the same approach, in fact even the same code, In all my apps (the ones that are location-aware that is) and I thought I’d share it with you. It’s basically some members, event handlers and a background method for initializing positioning.

1) some members used in the viewmodel (or even better, a base viewmodel)..

        public virtual GeoCoordinate CurrentLocation
        {
            get
            {
                if (IsInDesignMode)
                {
                    return new GeoCoordinate(59.36106, 17.87462);
                }
                return GeoHelper.Watcher.Position.Location;
            }
        }

        private string progressText;
        public bool HasWiredPositioningEvents { get; set; }
        public bool PreventLoading { get; set; }
        public bool PositioningStatusOk { get; set; }
        private IDisposable locationSubscriber = null;

        public delegate void OnPositioningReady();
        public event OnPositioningReady PositioningReady;

2) a WireUpPositioning method that takes care of most of the location details..

        public virtual void WireUpPositioning()
        {
            if (PreventLoading)
                return;

            if (Settings.PositioningAllowed)
            {
                if (!HasWiredPositioningEvents)
                {
                    HasWiredPositioningEvents = true;
                    GeoHelper.Watcher.StatusChanged += new System.EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
                    GeoHelper.Watcher.PositionChanged += new System.EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

                    ProgressText = "Determining your position..";

                    // background work - don't want to halt the UI while waiting..
                    ThreadPool.QueueUserWorkItem((o) =>

                    locationSubscriber = Observable.Return(GeoHelper.Start())
                        .Subscribe(x =>
                        {
                            if (!x)
                            {
                                // Start() failed, usually caused by positioning turned off..
                            }
                            else
                            {
                                SmartDispatcher.BeginInvoke(() =>
                                    {
                                        PositioningStatusOk = true;
                                        if (PositioningReady != null)
                                        {
                                            PositioningReady();
                                        }
                                    });
                            }
                        }
                    , ex =>
                    {
                        // exception caught..
                        ProgressText = null;
                    }
                    , (() => ProgressText = null)));
                }
            }
            else
            {
                HasWiredPositioningEvents = false;
                GeoHelper.Watcher.StatusChanged -= watcher_StatusChanged;
                GeoHelper.Watcher.PositionChanged -= watcher_PositionChanged;
                GeoHelper.Stop();
            }
        }

3) simple event handlers to travel the notification all the way up..

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            SmartDispatcher.BeginInvoke(() =>
            {
                this.RaisePropertyChanged("CurrentLocation");
            });
        }

        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            if (e.Status == GeoPositionStatus.Ready)
            {
                ProgressText = null;
                PositioningStatusOk = true;
            }
            else
            {
                PositioningStatusOk = false;
                if (e.Status == GeoPositionStatus.Initializing)
                {
                    ProgressText = "Initializing positioning..";
                }
                if (e.Status == GeoPositionStatus.Disabled)
                {
                    // handle positioning turned off / disabled if you need to..
                    ProgressText = null;
                }
                if (e.Status == GeoPositionStatus.NoData)
                {
                    ProgressText = "Positioning unavailable..";
                }
            }
            SmartDispatcher.BeginInvoke(() => 
                {
                    RaisePropertyChanged("PositioningStatusOk");
                    RaisePropertyChanged("CurrentLocation");
                }
                );
        }

4) the initializer I use is from a simple static helper class called GeoHelper from my Extensions library that holds a GeoCoordinateWatcher and methods to start/stop it.

    //
    // Copyright (c) 2012 Peter Drougge
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //    http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    //
    public static class GeoHelper
        {
            private static GeoCoordinateWatcher watcher;
            public static GeoCoordinateWatcher Watcher 
            { 
                get
                {
                    if (watcher == null)
                    {
                        watcher = new GeoCoordinateWatcher( GeoPositionAccuracy.High);
                    }
                    return watcher;
                }
            }


            public static bool IsCoordinatesValid(double latitude, double longitude)
            {
                if (latitude!=null && longitude!=null)
                {
                    try
                    {
                        GeoCoordinate gc = new GeoCoordinate(latitude, longitude);
                        return true;
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
                return false;
            }

            public static bool Start()
            {
                if (watcher.Status!=GeoPositionStatus.Initializing && watcher.Status!=GeoPositionStatus.Ready)
                {
                    return watcher.TryStart(false, new TimeSpan(0,0,30));
                }
                return true;
            }
            public static void Stop()
            {
                watcher.Stop();
            }
        }

that’s it. All you now have to do is place a call to WireUpPositioning() somewhere appropriate in the start of your app.