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

Building a RSS reader for Windows Phone 7 – Designing the structure

08.05.2010
| 23599 views |
  • submit to reddit

This is an article composed of two distinct parts. In the first part, I am describing the UI and structural aspects of the application while in the second part I am describing the application logic.

Getting Started

With the multitude of apps being developed for Windows Phone 7 at this moment, I haven’t seen any RSS readers, so I decided to write my own - just for the fun of it. Thinking about a very basic application workflow, I came up with this generalized idea:

There is a view that displays the feed contents – the title and a short overview of the item (details). That's what the user is interested in. There could be an unlimited number of feeds that are aggregated, but at the end, the contents for each feed are displayed together with others in the main view. Can be a bit messy, but at this point I am experimenting.

The end-user is able to manage the feeds by defining a collection of feed URLs that are later on stored as application settings in the isolated storage. Those URLs are considered aggregation sources.

The data retrieved from feeds is stored in a non-persistent manner in a dictionary. When the application is closed or deactivated, the data is lost and when the application is launched again it should be re-aggregated.

Working on the solution

I created a simple Windows Phone 7 Application (Silverlight). I started with the main page, and I modified its XAML markup to include a list. This was added to the existing Grid.

<Grid x:Name="ContentGrid" Grid.Row="1">
<ListBox ItemsSource="{Binding FeedItems}" Margin="13,0,13,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,10,0,10">
<TextBlock x:Name="ItemName" Text="{Binding ItemTitle}" Style="{StaticResource PhoneTextNormalStyle}"></TextBlock>
<TextBlock x:Name="ItemDetails" Text="{Binding ItemDetails}" Style="{StaticResource PhoneTextSubtleStyle}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

I am defining a custom data template for each item, since there will be the title and feed entry details displayed in one item. Don’t look at the ItemsSource and Text properties at this time – I will talk about the binding endpoints later on.

Also, on the main page there will be the application bar that will allow quick access to some feed tools – refreshing the existing items and managing feed URLs. So the following XAML snippet is added to the main page:

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem x:Name="reloadFeeds" Text="reload feeds" Click="reloadFeeds_Click" ></shell:ApplicationBarMenuItem>
<shell:ApplicationBarMenuItem x:Name="manageFeeds" Text="manage feeds" Click="manageFeeds_Click"></shell:ApplicationBarMenuItem>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

If you are wondering what an application bar is, here is what it looks like:

That is pretty much it for the main page. Obviously, you can (and you should) change the application and page title.

The next step is creating the page that will be displaying the list of feed URLs and will allow the end user to manage those. I added a portrait page to the solution and named it ManageFeeds.xaml.

Its default structure is left intact, but I added an additional grid in the second row of the existing layout grid:

<Grid x:Name="ContentGrid" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="400"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ListBox x:Name="MainList" Margin="13,0,13,0" Grid.Row="0" ItemsSource="{Binding FeedList}"></ListBox>
<TextBlock Text="FEED URL:" Grid.Row="1" FontSize="25" Margin="10,35,0,0"></TextBlock>
<TextBox x:Name="urlHolder" Grid.Row="1" Margin="120,10,70,10"></TextBox>
<Button Grid.Row="1" Margin="400,10,0,10" Content="+" FontSize="30" Click="Button_Click"></Button>
<Button Grid.Row="2" Content="REMOVE SELECTED" Click="Remove_Click"></Button>
</Grid>

Here I have three separate rows. The first one is used to hold the list of feed URLs, the second one is used to hold the TextBox control that will contain a new URL and an Add button, while the third row only holds a Remove Selected button that will let the user remove the selected item out of those that are currently registered. Once again, don’t look at the binding endpoints for now.

Overall, when you run the application, the page looks like this:

To make working with RSS feeds easier, I created a helper class, called FeedData, that is placed inside the FeedHelper folder that you should create:

The structue of the above mentioned class is relatively simple for now:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WP7_FeedReader.FeedHelper
{
public class FeedData
{
public ObservableCollection<string> FeedList { get; set; }
}
}

I will be using the FeedList collection to store the list of feed URLs (temporary - later on those will be transfered to isolated storage).

In the App.xaml.cs I am referencing a FeedData class instance and populating the FeedList property with existing saved URLs. These URLs are stored in the isolated storage as application settings. Since at this point I am not using any other settings, I am simply considering an entry in  IsolatedStorageSettings.ApplicationSettings to be a user-defined feed URL.

public static FeedHelper.FeedData Data;

// Constructor
public App()
{
Data = new FeedHelper.FeedData();
Data.FeedList = new ObservableCollection<string>();
if (System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Count != 0)
{
foreach (string key in System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.Keys)
{
Data.FeedList.Add(System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings[key].ToString());
}
}

UnhandledException += Application_UnhandledException;
InitializeComponent();
InitializePhoneApplication();
}
I have designed the application that way, so there is a main model used to display an item, and an item model, that will represent each feed item separately. This principle is bound to two separate classes I am going to create: MainModel and ItemModel.

In your solution, create a folder called ViewModel and create two new class files – MainModel.cs and ItemModel.cs inside it. Now, for the ItemModel, I defined the following class structure:

using System;
using System.ComponentModel;

namespace WP7_FeedReader.ViewModel
{
public class ItemModel : INotifyPropertyChanged
{
private string itemTitle;
public string ItemTitle
{
get { return itemTitle; }
set
{
if (value != itemTitle)
{
itemTitle = value;
NotifyPropertyChanged("ItemTitle");
}
}
}

private string itemDetails;
public string ItemDetails
{
get { return itemDetails; }
set
{
if (value != itemDetails)
{
itemDetails = value;
NotifyPropertyChanged("ItemDetails");
}
}
}

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

The properties will represent the feed item title and details accordingly. Instances of this class will be passed to the MainModel, that has an ObservableCollection used specifically to store feed items.

I defined the structure for MainModel the following way:

using System;
using System.Collections.ObjectModel;
using System.IO.IsolatedStorage;

namespace WP7_FeedReader.ViewModel
{
public class MainModel
{
public ObservableCollection<ItemModel> FeedItems {get; set;}
}
}

The FeedItems property is modifed publicly, specific to the current instance - a refreshed item list will automatically re-bind the ListBox on the main page.

Now that you know the structure of MainModel and ItemModel, you should also know that App.xaml.cs is also the place where the MainModel instance is initialized for the main page to use:

public static ViewModel.MainModel Model;

Inside the App constructor:

Model = new ViewModel.MainModel();

You can see where the binding is pointing to, but you need to explicitly specify the DataContext for each page. First of all, in the main page, you need to set the DataContext to the MainModel instance defined in App:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
this.DataContext = App.Model;

base.OnNavigatedTo(e);
}

The ManageFeeds page should have its DataContext set to the known FeedData instance:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
this.DataContext = App.Data;
base.OnNavigatedTo(e);
}

You can see now that all binding links are satisfied, since proper class instances are referenced.

The 'skeleton' for the RSS reader is ready, so it is now time to work on the logic of the application, that will be covered in the next article.