Click here to Skip to main content
Click here to Skip to main content

Netflix Browser for Windows Phone 7 - Part 1

, 17 Mar 2011
Rate this:
Please Sign up or sign in to vote.
Learn how to use the Pivot and Panorama controls, page navigation, OData and more!

I have created a video of the application.

Contents

Introduction

With the growing excitement around Windows Phone 7 and Daniel writing Windows Phone 7 Unleashed, I couldn’t resist getting involved in the space. Afterall, I have the advantage of an early preview of Daniel’s book. So I downloaded the tools and started playing around. I wanted to explore the Panorama and Pivot controls, and came up with a neat demo application that uses Netflix data, and showcases the Pivot and Panorama controls as well as OData, page navigation, WrapPanel and more. This article will be in part an overview of the Panorama and Pivot controls, and in part a walkthrough of the demo application.

Note: As I worked through the article, the number of pages kept growing and so I have split the article into two parts. Part 2.

Background

The final Windows Phone Developer Tools have been released, and with that, among other things, we have the official release of two navigation controls: the Pivot & Panorama. These controls are vital to the visual user experience on Windows Phone, and the phone's built-in applications use them extensively. Thus, undoubtedly, you will find yourself using them a lot. This is not to say, however, that they are a suitable choice for all applications. As these controls are quite new and unique to Windows Phone (at least currently), there may be some confusion in understanding them. There are several resources available. The particularity useful ones include: Windows Phone Design Days – Pivot and Panos video presented by Amy Alberts and Chad Roberts, and the UI design and interaction guide for Windows Phone 7. I will be drawing on these resources in the overview below.

Prior to the official Microsoft release of these controls, there were some alternatives such as Stephane Crozatier’s Panorama & Pivot controls available on Codeplex. For those who built their applications with these early controls, the advice is to migrate to the official controls. Fortunately Stephane Crozatier has written a transition guide.

What Will be Covered

  • Panorama Control
  • Pivot Control
  • String Formatting
  • Consuming Odata (part 2)
  • Page Navigation (part 2)
  • Progress Bar (part 2)
  • WrapPanel (part 2)

The Demo Application

The demo application is a Panorama application that allows users to browse through Netflix data. At the top layer the user is presented with a list of genres, new releases and highest rated movies. The user can then drill down into each movie to get movie details. Selecting a genre from the genre list will take the user to a Pivot, which lists movies for the selected genre; representing the data in three different ways: all movies for that genre, movies sorted by year, and movies sorted by average rating. In an ideal situation I would like to see the list of all genres to be only the top level genres instead of a very long list of genres and subgenres, but there wasn’t an easy way of querying this.

Prerequisites

  • Windows Vista or Windows 7
  • Windows Phone 7 Developers Tools which includes Visual Studio Express 2010 for Windows Phone, Windows Phone Emulator, Expression Blend 4 for Windows Phone, and XNA Game Studio 4.0.
    • Visual Studio Express 2010 and Expression Bled 4 will only be installed if you do not already have them installed.
    • If you have previously installed the Beta Tools, you will have to uninstall it before installing the final tools. Note that the installation may take some time. Leave the installation running, it will eventually complete.
  • Silverlight for Windows Phone Toolkit
  • OData Client Library for Windows Phone 7 (The one currently available is from March 2010)

Understanding the Pivot and Panorama Controls

The Pivot and Panorama are two layout controls that help you represent data on the phone in a unique way. They have several things in common. They both hold a number of horizontally arranged individual views (sections). They are visually quite similar; both show a bit of the off-screen content, have titles and section titles (see Figures 1 and 2). Both controls have built-in touch navigation that allows the user to navigate left to right between the different sections using the pan and flick touch-gestures, and up and down touch gestures for when the section’s content doesn’t fit into the height of the screen boundaries. The left to right navigation is cyclical (i.e. after the last section, the first section appears).

The controls are also quite different. This is mainly because they each serve a different purpose. The Panorama is meant to entice the user to explore; whereas the Pivot is about tasks and getting something done. As Amy Alberts and Chad Roberts say in their presentations, Pivots are efficient, focused, habitual whereas the Panorama is expansive, dynamic, inviting exploration. We can see this differentiation in Figure 1 and 2, where the Panorama offers a visually appealing experience, enticing the user with an attractive background, large title, variety of UI controls, animation, thumbnails etc, while the Pivot appears less appealing. There is also one other difference, and that is the content width of each view. The Panorama views usually span over screen boundaries, whereas the Pivot content is confined to the screen width; fitting within the screen. Users can navigate through the pivot sections not only via the left to right gestures, but also by directly selecting the Pivot Title.

Panorama

The Panorama is a wide horizontal canvas that spans over screen boundaries. The canvas is sliced into several different views and uses layered animations and UI controls to represent data in different ways, i.e. lists, grids, buttons etc. For usability issues the number of these sections should be limited to four, but the width and height of each section can vary. The panorama tends to be explorative, essentially working as the top layer to several other experiences. As the Panorama is intended to coax the user to explore, it should show content that is interesting, tailored for that user; it should not feel generic. We should also not want to overwhelm the user with too much data. As Jeff Wilcox says “Panorama is meant to be the starting space, think white space not tons of data”. The Panorama contains data, and links that take the user to more detailed pages of the content, for example to the Pivot. The user then transits from the exploratory mode of the Panorama to the more focused mode of the Pivot.

Figure 1: Panorama

As you can see in Figure 1, some pixels of the next section are showing to the right. This is to hint the user that there is more content to explore. A Panorama application should offer a visually appealing experience. This can be achieved with an attractive background. It can be either a single colour or a background image. According to the design guidelines the image size should be 800 pixels high and 480 to 1000 pixels wide. The image could possibly be wider but no more that 2000 px as the image will be clipped at this width. Note that an image with a height of less then 800 pixels will be stretched to that height without constraining proportions. The background image is the bottom layer of the Panorama with the different sections overlaying on top of it. You should not attempt to have the background dependent on the content because they are not going to match up. As you can see in the video, the Panorama title moves in different rate then its section titles as the user moves thought the Panorama.

Pivot

Some regard the pivot being a lot like the TabControl for the phone. The pivot also has several different views (sections). It is recommended to limit the number of sections to 7 to ensure users can comprehend what is presented to them.

Unlike with the Panorama where the content may go beyond the screen boundaries, the Pivot content is confined to the screen width. Also, contrary of the Panorama, the Pivot doesn’t display the few pixels of the content of the next section, but rather gives users an indication how the data is filtered through the section titles at the top of the screen (See Figure 2).

Figure 2: Pivot

As we said before, Pivots are about getting something done, and so Pivots are suited to have an ApplicationBar. This is contrary to Panorama based applications which should not show an ApplicationBar. Therefore, if your page needs an application bar use a Pivot instead of a Panorama. Pivots are designed to represent data or items of similar type. For example, pivots can be used as filters for similar content around the same task flow. A good example of a pivot is the Email application, which shows all emails in one view, flagged emails in another, unread email in another, etc.

Things to Avoid

You should not place a Pivot inside a Panorama, or nest Pivots. Also you should not attempt to use either the Pivot or Panorama for creating a wizard flow. As Amy Alberts says, the user sees Panoramas and Pivots as distinct areas of data being surfaced to them, and not as a flow of UI that the user walks through. So for a wizard use a page flow instead. It is also recommended not to use a map control inside a Pivot or Panorama. You should also avoid animating the panorama title or section titles as they are going to be moving as the user moves through the control. Also avoid dynamically changing the Panorama title. The UI guidelines also state not to override the horizontal pan and flick functionality because it collides with the interaction design of the controls. Also keep to the recommended number of views, seven for Pivot and four for Panorama. And keep in mind that the user should never lose his or her place inside the Panorama, and should always know how to get back. You would also not want to have a Panorama, and every link on the Panorama, taking you to a Pivot.

The Demo Application: Getting Started

Both controls have custom templates that you can use to create the Pivot or Panorama. You can either create a new Pivot or Panorama Application Project or, for an existing project, you can add a new Pivot or Panorama Page. We will demonstrate both ways. Both controls can also be added through Visual Studio into the Toolbox and then dragged onto a page.

We begin by creating a new Panorama Application Project. In Visual Studio go File -> New -> Project and select Windows Phone Panorama Application found under the Silverlight for Windows Phone option (see Figure 3).

Figure 3: Create a new Windows Phone Panorama Application

Once the project is created, we can see that the template provided us with a project structure, some sample data, and formatted views for the Panorama. Visual Studio also provides us with a nice feature to view the panorama sections in the designer. The designer will show the currently selected panorama item xaml (see Figure 4).

Figure 4: Panorama in Visual Studio designer.

The Phone application template also comes with the following default images:

  • application icon (ApplicationIcon.png)
    • The application icon is used in the quick launch screen.
  • background image of an application Tile (background.png)
    • The application Tile is displayed for a quick launch on the start experience, once the user has pinned it there. You can pin the application to the start experience in the emulator by pressing the application icon in the quick launch screen. After a second or two you should get a context menu with the option to either pin to start or uninstall (see Figure 6). The Tile title and background image can be set in application properties as shown in Figure 5. You will be able to change the Tile title, its background image, and a counter through Tile Notification to create a personal experience for the user, but this is beyond the scope of this article.
  • splash screen (SplashScreenImage.jpg)
    • The splash screen is shown before the application gets to the first page. There are some rules for creating the splash screen such as the width and height of the image has to be 480 x 800 pixels, the image name must be SplashScreenImage.jpg and the Build Action property must be set to Content.

Figure 5: Set Application title, icon, Tile title and Tile background image 

Figure 6: Pin application to the start screen

Panorama Control

Working with the Panorama control is straight forward. The excerpt shown below is taken from the Panorama application template. As we can see the Panorama control holds two PanoramaItem content controls. The PanoramaItem controls host the panoramic content, and these are the views or sections we talked about in the overview above. As per the recommendations there should not be more than four PanoramaItem controls within a Panorama control. In the demo we use three. Although we do not use this in the demo, the PanoramaItem controls can be added and removed programatically at runtime. The Panorama control contains a Title and a Background property. The Title in the excerpt below is specified as text, but it has a TitleTemplate dependency property and thus can also be set through data binding. This also applies to the Header property of the PanoramaItem. As you can see below, the panorama background is applied as an image with an ImageBrush, and we use the same in the demo, but you can also use GradientBrush or SolidColorBrush. If you use a background image, its Build Action should be set to Resource to ensure that it is shown as soon as the first page of the application starts. Setting the Build Action to Content means that it gets loaded asynchronously. Note in the excerpt below that all left and right margins of the panorama items are set to 12px. This is for UX reasons and applies to the Pivot conrol too.

<!--Panorama control-->
<controls:Panorama Title="my application">
  <controls:Panorama.Background>
    <ImageBrush ImageSource="PanoramaBackground.png"/>
  </controls:Panorama.Background>

  <!--Panorama item one-->
  <controls:PanoramaItem Header="first item">
    <!--Double line list with text wrapping-->
    <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel Margin="0,0,0,17" Width="432">
            <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" 
                Style="{StaticResource PhoneTextExtraLargeStyle}"/>
            <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" 
                Margin="12,-6,12,0" 
                Style="{StaticResource PhoneTextSubtleStyle}"/>
          </StackPanel>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </controls:PanoramaItem>

  <!--Panorama item two-->
  <!--Use 'Orientation="Horizontal"' 
         to enable a panel that lays out horizontally-->
  <controls:PanoramaItem Header="second item">
    <!--Double line list with image placeholder and text wrapping-->
    <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <!--Replace rectangle with image-->
            <Rectangle Height="100" Width="100" Fill="#FFE5001b" 
                Margin="12,0,9,0"/>
            <StackPanel Width="311">                                    
              <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" 
                Style="{StaticResource PhoneTextExtraLargeStyle}"/>
              <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" 
                Margin="12,-6,12,0" 
                Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
          </StackPanel>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </controls:PanoramaItem>
</controls:Panorama>

For the demo application I modified the sample Panorama control. I changed the Panorama Background, and Title, modified the PanoramaItem layout, set the PanoramaItem Headers, and replaced the binding expressions. I also defined a new PanoramaForegroundBrush. The TextBox Foreground styles that are used in the Panorama template provide automatic support for the phone dark and light themes. The behaviour is that the text within the Panorama is white under the dark theme and changes to black under the light theme. The black text didn’t work with the Panorama background and so I defined a new PanoramaForegroundBrush, and set the Foreground Property of each TextBlock within the Panorama control to the new brush.

<UserControl.Resources>
	<SolidColorBrush x:Key="PanoramaForegroundBrush" Color="#FFf6f0d9"/>
</UserControl.Resources>

The first Panorama section shows a list of all genres. We set the section Header to 'genres' and use a ListBox control to allow the user to navigate vertically through the list (see below).

<!--Panorama item one-->
<controls:PanoramaItem Header="genres" >
  <ListBox x:Name="GenreListBox"  Margin="0,0,-12,0" 
       ItemsSource="{Binding Genres}" 
       SelectionChanged="GenreListBoxSelectionChanged">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Margin="0,0,0,17" Width="432">
          <TextBlock Text="{Binding Name}" TextWrapping="Wrap" 
                 Foreground="{StaticResource PanoramaForegroundBrush}" 
                 Style="{StaticResource PhoneTextLargeStyle}"/>
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</controls:PanoramaItem>

The second Panorama section shows new releases. The information is depicted as a small thumbnail of the movie, together with a title, average rating, and a date that the Dvd is available from. Again we set the Header and use the ListBox control to layout the content (see below).

<!--Panorama item two-->
<controls:PanoramaItem Header="new releases" >
  <ListBox Margin="0,0,-12,0" x:Name="NewTitlesListBox" 
       ItemsSource="{Binding NewTitles}" 
       SelectionChanged="TitlesListBoxSelectionChanged">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,20">
          <Image  CacheMode="BitmapCache" Source="{Binding BoxArt.LargeUrl}" 
              Margin="12,0,9,0"/>
          <StackPanel Width="311">
            <TextBlock Text="{Binding Name}" TextWrapping="Wrap"  
                   Foreground="{StaticResource PanoramaForegroundBrush}" 
                   Style="{StaticResource PhoneTextLargeStyle}"/>
            <StackPanel Orientation="Horizontal" >
              <TextBlock  Margin="12,5,5,5" Text="Rating:" 
                    Foreground="{StaticResource PanoramaForegroundBrush}" 
                    Style="{StaticResource PhoneTextNormalStyle}"/>
              <TextBlock  Margin="0,5,0,5" Text="{Binding AverageRating}" 
                    Foreground="{StaticResource PanoramaForegroundBrush}" 
                    Style="{StaticResource PhoneTextNormalStyle}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
              <TextBlock  Margin="12,5,5,20" Text="Available: " 
                    Foreground="{StaticResource PanoramaForegroundBrush}" 
                    Style="{StaticResource PhoneTextNormalStyle}"/>
              <TextBlock Margin="0,5,0,20" Text="{Binding Dvd.AvailableFrom, 
                     Converter={StaticResource StringFormatConverter},
                      ConverterParameter=\{0:d MMMM yyyy\}}" 
                     TextWrapping="Wrap" 
                     Foreground="{StaticResource PanoramaForegroundBrush}" 
                     Style="{StaticResource PhoneTextNormalStyle}"/>
            </StackPanel>
          </StackPanel>
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</controls:PanoramaItem

String Format Converter

In the second PanoramaItem there is a date field which required formatting. In Silverlight 4, you can specify string formatting directly in the Binding expression, but because Windows Phone is based on Silverlight 3 we need to use a Converter. Luckily Daniel wrote such a converter some time ago, and so I have incorporated his StringFormatConverter class in my demo. Thank you darling. To use the StringFormatConverter class, add a namespace reference in the MainPage.xaml, like so:

xmlns:converter="clr-namespace:NetflixBrowser.Helpers"

Add the converter as a resource as shown below.

<UserControl.Resources>
	<converter:StringFormatConverter x:Key="StringFormatConverter" />
</UserControl.Resources>

Specify the ConverterParameter attribute to define the format:

<TextBlock Margin="0,5,0,20" Text="{Binding Dvd.AvailableFrom, 
	Converter={StaticResource StringFormatConverter}, 
	ConverterParameter=\{0:d MMMM yyyy\}}" 
	TextWrapping="Wrap" 
	Foreground="{StaticResource PanoramaForegroundBrush}" 
	Style="{StaticResource PhoneTextNormalStyle}"/>

Pivot Control

We add the Pivot control as a new Pivot Page. In the Solution Explorer right click on the project, navigate to Add -> New Item, and select Windows Phone Pivot Page (see Figure 7)

Figure 7: Add a new Windows Phone Pivot Page

The following excerpt shows the pivot control template. We can see many similarities with the Panorama control. Just like the Panorama control, the Pivot Control holds PivotItem content controls. It has a Title and a Background. The Title can be set as text or it can be databound, just like with the Panorama Control. Again, this is true for the PivotItem Headers. The Pivot can also have its background set to an image. We do not set the Pivot Background property in the Demo application, and thus the Pivot background behaves according to the dark or light theme set on the phone (which means that it will be either black or white).

<!--Pivot Control-->
<controls:Pivot Title="MY APPLICATION">
	<!--Pivot item one-->
	<controls:PivotItem Header="item1">
	  <Grid/>
	</controls:PivotItem>

	<!--Pivot item two-->
	<controls:PivotItem Header="item2">
	  <Grid/>
	</controls:PivotItem>
</controls:Pivot>

In the demo application we use the Pivot control to show movies for a selected genre. The Pivot page is called GenreDvds.xaml. Just like with the Panorama control I modified the template, changing the Pivot title, headers etc. Because the GenreDvds.xml page is being navigated to from the Panorama page, displaying DVDs for the selected genre, I set the Pivot Title with a Binding expression as shown below:

<!--Pivot Control-->
<controls:Pivot  x:Name="SelectedGenre" Title="{Binding SelectedGenreName}" 
	Visibility="{Binding Loaded, 
         Converter={StaticResource BooleanToVisibilityConverter}, 
	ConverterParameter=Visible}">
	.
	.
	.
</controls:PivotItem>

In the above excerpt you can also see that we are dynamically setting the Pivot’s visibility. This will be covered in Part II of this article under the section called Progress Bar.

The Pivot control has three sections. All three sections are layed out in the same way depicting the movie thumb image, title, short synopsis, average rating and availablity.

<!--Pivot item one-->
<controls:PivotItem Header="all">
  <ListBox Margin="0,0,-12,0" ItemsSource="{Binding GenreTitles}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,20">
          <Image  CacheMode="BitmapCache" Source="{Binding BoxArt.LargeUrl}" 
            Margin="12,0,9,0"/>
          <StackPanel Width="311">
            <TextBlock Text="{Binding Name}" TextWrapping="Wrap" 
                   Style="{StaticResource PhoneTextLargeStyle}"/>
            <TextBlock Text="{Binding ShortSynopsis}" TextWrapping="Wrap" 
                Margin="12,-6,12,10" 
                   Style="{StaticResource PhoneTextSubtleStyle}"/>            
            <StackPanel Orientation="Horizontal" >
              <TextBlock  Margin="12,5,5,5" Text="Rating:" 
                    Style="{StaticResource PhoneTextNormalStyle}"/>
              <TextBlock  Margin="0,5,0,5" Text="{Binding AverageRating}" 
                    Style="{StaticResource PhoneTextNormalStyle}"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
              <TextBlock  Margin="12,5,5,20" Text="Available: " 
                Style="{StaticResource PhoneTextNormalStyle}"/>
              <TextBlock Margin="0,5,0,20" 
                     Text="{Binding Dvd.AvailableFrom, 
                    Converter={StaticResource StringFormatConverter}, 
                     ConverterParameter=\{0:d MMMM yyyy\}}" 
                     TextWrapping="Wrap" 
                   Style="{StaticResource PhoneTextNormalStyle}"/>
            </StackPanel>
          </StackPanel>
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</controls:PivotItem>>

Conclusion

In this article we explored the Pivot and Panorama controls, introduced the demo application, saw how to add the controls to your project, and had a look at the Pivot and Panorama templates. In part II of this article we will cover OData, WrapPanel, Page Navigation, and the Progress Bar. I hope you found this article useful. If you enjoyed my article, please rate it and maybe share your thoughts below.

History

  • October 2010: Initial release.

References

Panorama background image: Red background by Jana Koll

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Katka Vaughan
Software Developer Outcoder
Switzerland Switzerland
Katka has several years of experience working in software development in the areas of market research and e-commerce. She has wide ranging experience in developing Java, ASP.Net MVC, ASP.Net, WPF, Silverlight, and Windows Phone applications. Katka is an Aussie/Czech girl currently based in Zurich, Switzerland.
 
Open source projects: Calcium SDK
Group: Windows Phone Experts
Proud creator of: Surfy browser

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberfredatcodeproject22-May-13 1:16 
GeneralMy vote of 2 PinmemberBaseem Najjar25-Jun-12 0:08 
GeneralMy vote of 4 PinmemberAbel461-Mar-11 3:00 
GeneralRe: My vote of 4 PinmemberKatka Vaughan17-Mar-11 5:33 
GeneralMy vote of 5 PinmemberNtr2ntr_kiran4-Jan-11 17:28 
GeneralRe: My vote of 5 PinmemberKatka Vaughan7-Jan-11 23:44 
GeneralMy vote of 5 Pinmemberprasad0220-Dec-10 19:01 
GeneralRe: My vote of 5 PinmemberKatka Vaughan20-Dec-10 21:58 
GeneralMy vote of 5 PinmemberAtlas20029-Nov-10 17:08 
GeneralRe: My vote of 5 PinmemberKatka Vaughan9-Nov-10 22:13 
GeneralMy vote of 5 PinmemberAbhinav S7-Nov-10 5:56 
Good article.
GeneralRe: My vote of 5 PinmemberKatka Vaughan7-Nov-10 10:12 
GeneralThat's brilliant... PinmemberGary Noble7-Nov-10 1:17 
GeneralRe: That's brilliant... PinmemberKatka Vaughan7-Nov-10 2:50 
GeneralMy vote of 5 PinmvpAbhishek Sur27-Oct-10 23:55 
GeneralRe: My vote of 5 PinmemberKatka Vaughan28-Oct-10 0:06 
GeneralMy vote of 5 PinmemberPetr Pechovic25-Oct-10 5:41 
GeneralRe: My vote of 5 PinmemberKatka Vaughan25-Oct-10 7:12 
GeneralMy vote of 5 PinmvpAbhijit Jana23-Oct-10 0:18 
GeneralRe: My vote of 5 PinmemberKatka Vaughan23-Oct-10 2:43 
GeneralMy vote of 5 PinmemberRaul Mainardi Neto22-Oct-10 0:22 
GeneralRe: My vote of 5 PinmemberKatka Vaughan22-Oct-10 1:26 
GeneralMy vote of 5 PinadminChris Maunder19-Oct-10 4:05 
GeneralRe: My vote of 5 PinmemberKatka Vaughan19-Oct-10 4:41 
GeneralRe: My vote of 5 PinmvpSacha Barber26-Oct-10 2:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 17 Mar 2011
Article Copyright 2010 by Katka Vaughan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid