.NET Zone is brought to you in partnership with:

Den is a DZone Zone Leader and has posted 460 posts at DZone. You can read more from them at their website. View Full User Profile

Porting Visual Studio Achievements for WP to Windows 8 - Minor problems and data acquisition

03.12.2012
| 4617 views |
  • submit to reddit

This is the next post in the series describing how to port a Windows Phone application to Windows 8. Yesterday, I showed how easy it was to move the basic layout and fundamental bindings. Today I am fixing some minor issues, as well as show how to get the basic user data.

First things first, you probably noticed that even though my Image controls are bound to a Uri source from a Niner model, the images are not displayed. Therefore, I am not getting the profile pictures for each user I am tracking via my application. I am not sure whether this is a bug or not, but apparently direct binding through XAML doesn't work too well for images. Therefore, I had to think of a workaround. Instead of binding the URL to the Source property, I am binding it to the Tag one. Then, I am using an Loaded event handler that will actually load the image. The XAML will look like this:

<Image Tag="{Binding Avatar}" Loaded="NinerImageLoaded" Height="78" Width="78" HorizontalAlignment="Left" Margin="10,0,0,0"></Image>

Remember, that the Avatar property is located in the Niner model that represents a Channel9 user. Now, the code-behind for the event handler I mentioned above looks like this:

private void NinerImageLoaded(object sender, RoutedEventArgs e)
{
    Image entity = (Image)sender;
    BitmapImage image = new BitmapImage(new Uri(entity.Tag.ToString(), UriKind.Absolute));

    entity.Source = image;
}

This was easy, and now we get a sample image for each user entry (based on the code I showed in the previous article):

Let's get the actual data now, since handling sample units is not exactly the purpose of this application. In the Windows Phone VSA application, I had a class called NinerReader that processed both JSON and HTML data. It was a bit complex, yet it did the job pretty well. You can familiarize itself with it by looking at the source code on CodePlex.

First of all, I will need to modify a batch of JSON manipulation code. Take a look at this snippet:

JsonValue obj = JsonObject.Parse(JSONContent);
JsonValue value = obj["Achievements"];

foreach (JsonValue aValue in value)
{
    Achievement achievement = new Achievement();
    achievement.Category = aValue["Category"];

This is an example of perfectly-working code inside a Windows Phone project. However, Visual Studio 11 gives me this in a Metro application:

'

Something is obviously wrong, and I need to find out what exactly.

NOTE: In a Windows 8 Metro application, you will no longer reference System.Json. Use Windows.Data.Json instead.

JsonObject.Parse(string) no longer returns a JsonValue, but rather a JsonObject. When I am reading an object subitem via obj[itemID], I get an IJsonValue instead of JsonValue.I must admit - JSON parsing got much better in Metro applications, and it makes it much easier to get the necessary data. With a little bit of refactoring, I changed my snippet to this:

JsonObject obj = JsonObject.Parse(JSONContent);
IJsonValue value = obj["Achievements"];

foreach (IJsonValue aValue in value.GetArray())
{
    Achievement achievement = new Achievement();
    achievement.Category = aValue.GetObject().GetNamedString("Category");

    try
    {
        DateTime dateEarned = new DateTime();
        DateTime.TryParse(aValue.GetObject().GetNamedString("DateEarned"), out dateEarned);
        achievement.DateEarned = dateEarned;

        achievement.Description = aValue.GetObject().GetNamedString("Description");
        achievement.FriendlyName = aValue.GetObject().GetNamedString("FriendlyName");
        achievement.Icon = new Uri(aValue.GetObject().GetNamedString("Icon"));
        achievement.IconSmall = new Uri(aValue.GetObject().GetNamedString("IconSmall"));
        achievement.Name = aValue.GetObject().GetNamedString("Name");
        string data = aValue.GetObject().GetNamedString("Points");
        achievement.Points = Convert.ToInt32(data);

        CurrentNiner.Achievements.Add(achievement);

        CurrentNiner.Points += achievement.Points;
    }
    catch
    {
        // Do something else here. Eventually.
        Debug.WriteLine("Achievement not earned");
    }
}

GetNamedString is a lifesaver here - finally a decent method instead of direct array referencing. It works in a similar way, so generally it should not cause major problems with legacy code.

Also, when invoking the action that should be triggered on completion, I was getting this:

This cross-thread problem can be easily mitigated with the help of CoreDispatcher, that is integrated by me in the App class - it can be instantiated when the first page is loaded. The idea itself was provided by Rob Caplan here.

If you prefer to handle the asynchronicity yourself, the worker thread can invoke back to the UI thread by calling InvokeAsync on the Xaml Window's Dispatcher property (which returns the App's Windows.UI.Core.CoreDispatcher) . 

this.Dispatcher.InvokeAsync(CoreDispatcherPriority.Normal, (s,invokeEventArgs) => { /* UI thread stuff */}, this, null);

The data acquisition layer is complete at this step. You can test it by using this snippet somewhere in the application:

NinerReader reader = new NinerReader();
reader.GetNiner("dennisdel", true, niner =>
{
    BindingPoint.Instance.Niners.Add(niner);
});

Your result should resemble this:

Also, you will most likely see some exceptions being logged in the Output dialog - that is normal, since those represent cases where I am trying to get the date when I earned an achievement that I haven't actually earned yet. You can safely ignore those for now.

Conclusion

I showed you that even though some Windows Phone code can be quite ramified and complex, there are only minor adjustments necessary to make it work with WinRT. The biggest aspect that you have to pay attention to is multi-threading, that is handled in a way that might be new for some WinPhone developers.