Mobile 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

Visual Studio Achievements for Windows Phone - User details & official project page

12.12.2011
| 2844 views |
  • submit to reddit

If you missed the previous two parts, you can easily find them here:

Today I am showing you how it is possible to view specific Niner details, given that you have that user added to the "watch list". First, you need to establish the main page structure. Something that would look like this:

Nothing extremely complicated, so I put together this XAML for UserDetail.xaml - that is the page that will be displaying the user information.

<phone:PhoneApplicationPage 
    x:Class="VisualStudioAchievements.UserDetail"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True"
    xmlns:local="clr-namespace:VisualStudioAchievements">

    <phone:PhoneApplicationPage.Resources>
        <local:BindingPoint x:Key="LocalBindingPoint"></local:BindingPoint>
    </phone:PhoneApplicationPage.Resources>
    
    <Grid DataContext="{Binding Path=CurrentNiner,Source={StaticResource LocalBindingPoint}}" x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="200"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions> 
        
        <StackPanel Orientation="Horizontal">
            <Image Height="200" Width="200" Source="{Binding Avatar}"></Image>
            <StackPanel>
                <TextBlock Foreground="Black" Text="{Binding Alias}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}" TextWrapping="Wrap"></TextBlock>
                <TextBlock Foreground="Gray" Text="{Binding Name}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}" TextWrapping="Wrap"></TextBlock>
                <TextBlock Foreground="Gray" Text="{Binding Caption}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}" TextWrapping="Wrap"></TextBlock>
                <TextBlock Foreground="Gray" Text="{Binding Points}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}" TextWrapping="Wrap"></TextBlock>
            </StackPanel>
        </StackPanel>

        <ListBox Grid.Row="1" ItemsSource="{Binding Achievements}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Height="140" Orientation="Horizontal">
                        <Image Height="64" Width="64" Source="{Binding Icon}"></Image>
                        <StackPanel>
                            <TextBlock Text="{Binding FriendlyName}" Foreground="Gray"></TextBlock>
                            <TextBlock Text="{Binding Description}" Foreground="Gray"></TextBlock>
                            <TextBlock Text="{Binding DateEarned}" Foreground="Gray"></TextBlock>
                            <TextBlock Text="{Binding Points}" Foreground="Gray"></TextBlock>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</phone:PhoneApplicationPage>

Let's clarify parts of this page, and I am going to start with namespace declarations in the header. There is a reference to xmlns:local:

xmlns:local="clr-namespace:VisualStudioAchievements"

This namespace reference points to the root of the project - the main namespace. I am using it to access the BindingPoint class - that is shown in the page resources section:

<phone:PhoneApplicationPage.Resources>
    <local:BindingPoint x:Key="LocalBindingPoint"></local:BindingPoint>
</phone:PhoneApplicationPage.Resources>

As a quick reminder, that is a class for global binding elements, like the collection of Niners (users of Channel 9) and the currently selected Niner. Speaking of which, it is now represented by a designated property:

using System;
using System.Collections.ObjectModel;

namespace VisualStudioAchievements
{
    public class BindingPoint
    {
        public static ObservableCollection<Niner> Niners { get; set; }

        public static Niner CurrentNiner { get; set; }
    }
}

Back on the topic of the main page, you probably noticed that the main grid has a DataContext set. This way I am making sure that all elements inside it will get data accessed through bound properties relative to the CurrentNiner property.

The rest is mainly layout - the Grid is split in two rows. The first one is the header that displays user metadata. The ListBox in the second row displays all achievements that were earned by the user. The DataTemplate is set accordingly, so that I can display pretty much all achievement information, like the image, number of points added for earning it, its description and friendly name.

Here comes the question - how exactly do I set CurrentNiner? When a new Niner is added, it is displayed on the main page:

When the application user decides to tap on one of the Niners, the page should switch to the detailed view. That's why I implemented two things in the ListBox that shows all registered Niners:

  • Binding the Tag property from the StackPanel in the DataTemplate to the user alias
  • Handling the Tap event handler for the StackPanel in the DataTemplate

Take a look at its declaration:

<ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Tap="StackPanel_Tap" Tag="{Binding Alias}" Orientation="Horizontal" Height="200">

The event handler itself doesn't contain anything special but selection and navigation code:

private void StackPanel_Tap(object sender, GestureEventArgs e)
{
    BindingPoint.CurrentNiner = (from c in BindingPoint.Niners where c.Alias == ((StackPanel)sender).Tag select c).Single();
    NavigationService.Navigate(new Uri("/UserDetail.xaml", UriKind.Relative));
}

Does it look ugly at this moment? Yes, but since we are focusing on the functionality right now, the fact that it works is what matters most. You can now navigate back and forth between the main and detail pages to view user details and achievement descriptions.

Project Page! You can now pull the Visual Studio Achievements for Windows Phone directly from CodePlex. In case you get confused by the snippets I post or you are too lazy to enter/copy all the code yourself, just head over here to get the latest source:

http://vsa.codeplex.com