WP7 getting started (5) – Using databound controls

This is the fifth in a series of blog posts describing how to get started with Windows Phone 7 development. It is written based on my own experience getting started with Windows Phone 7 development.

The previous entry, where I demonstrated how to retrieve and data from a REST based webservice is available here.

In that blog post I created a fairly naive application, which retrieves som Json data and manually assigns values to some labels on screen.

In this post I will demonstrate how to use Visual Studios databound application template to create an application, that can display the contents of an RSS feed.

Background

If, like me, you suddenly have a profound interest in the subject of having twins, you might create an application that displays all the latest stories from http://www.having-twins.com/.

A more likely example could be that you have an existing website/community or similar and would like to create a simple mobile app from it. You could then create an RSS feed on your site and then create an RSS driven application.

Fortunately for the lazy programmer, Microsoft has created a couple of project templates, that make it simple to get started.

Simple Datebound Application

Since this is going to be an app that displays a list of news entries drawn from a single source, I will use the template “Windows Phone Databound Application”.

Lets examine the project that was created for us. The main application screen has the basic Windows Phone 7 application layout, with the top third of the screen reserved for application and page name, and below there is a list of items, each with a title and a summary. When the users taps on an item, he is taken to the details screen.

Design datasource

First thing you might notice is, that the design view of the template application is filled with example data already:

Now, where did that come from? Well, if we examine the xaml for the view, we’ll find that Visual Studio has added a d:DataContext declaration, that points to the file MainViewModelSampleData.

<phone:PhoneApplicationPage
    (...)
    d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
    (...)
>

This sample data corresponds to the example viewmodels MainViewModel and MainViewModel.Items.
Using this metod you can define your own example data or use the autogenerated data to see what your views will look like when you design them in Visual Studio or Expression Blend. Expression blend even has the ability to generate data for you, once you have defined your custom ViewModel.

Secondly, the controls are bound to properties in the datamodel using standard xaml-based databinding syntax {Binding PropertyName}.

    <!--Data context is set to sample data above and LayoutRoot contains the root grid where all other page content is placed-->
    <Grid x:Name="LayoutRoot">
        (...)
        <Grid>
            <ListBox ItemsSource="{Binding Items}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                      <StackPanel>
                          <TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" />
                          <TextBlock Text="{Binding LineTwo}" TextWrapping="NoWrap" />
                      </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </Grid>
    </Grid>

Notice that the ListBox binds to Items, which is an ObservableCollection<ItemViewModel> on MainViewModel and each <TextBlock> within the <ListBox.ItemTemplate> then binds to properties LineOne and LineTwo on the ItemViewModel.

Runtime datasource

When you run your application, you’ll notice that the running app displays another set of  data:

The “runtime one”, “runtime two”, etc data is default template data generated in MainViewModel.LoadData, which is called from MainPage.MainPage_Loaded.

/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public void LoadData()
{
    // Sample data; replace with real data
    this.Items.Add(new ItemViewModel() { LineOne = "runtime one", LineTwo = "Maecenas praesent accumsan bibendum", LineThree = "Facilisi faucibus habitant inceptos interdum lobortis nascetur pharetra placerat pulvinar sagittis senectus sociosqu" });
    (...)
    this.Items.Add(new ItemViewModel() { LineOne = "runtime sixteen", LineTwo = "Nascetur pharetra placerat pulvinar", LineThree = "Pulvinar sagittis senectus sociosqu suscipit torquent ultrices vehicula volutpat maecenas praesent accumsan bibendum" });

    this.IsDataLoaded = true;
}

To keep this example as simple as possible, the only thing I’ll change is which data we put into the items collection, so to download the RSS feed and use that data instead, the above lines are changed into.

/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public void LoadData()
{
    var webClient = new WebClient();
    webClient.DownloadStringCompleted += webClient_DownloadStringCompleted;
    webClient.DownloadStringAsync(new Uri("http://www.having-twins.com/Twins.xml"));
}

private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error != null) return;

    var reader = XmlReader.Create(new StringReader(e.Result));
    SyndicationFeed feed = SyndicationFeed.Load(reader);

    foreach (var item in feed.Items)
    {
        Items.Add(new ItemViewModel(){LineOne = item.Title.Text.Trim(), LineTwo = item.Summary.Text.Trim()});
    }
    this.IsDataLoaded = true;
}

This code downloads the rss-feed from http://www.having-twins.com/Twins.xml, parses it using SyndicationFeed (you must manually reference it from Program FilesMicrosoft SDKsSilverlightv4.0LibrariesClientSystem.ServiceModel.Syndication.dll) and uses the Title and Summary texts from that feed to populate the LineOne and LineTwo properties of the ItemViewModel.

When you run the app in the emulator, you’ll get a nice view like this (you’ll need to set TextWrapping to NoWrap on the TextBlocks):

Starting a browser

Finally, the feed from having-twins.com provides a link to the article and not the actual article, so when you click on an item in the list, we should start a webbrowser and go directly to the article on the website.

First we need to add a property to store the item url on the ItemViewModel:

private Uri _uri;
public Uri Uri
{
    get
    {
        return _uri;
    }
    set
    {
        if (value != _uri)
        {
            _uri = value;
            NotifyPropertyChanged("Uri");
        }
    }
}

Next we need to extract the url and store it per item, so we’ll change the line of code in webClient_DownloadStringCompleted to:

Items.Add(new ItemViewModel(){LineOne = item.Title.Text.Trim(), LineTwo = item.Summary.Text.Trim(), Uri = item.Links.First().Uri});

The final step is to start the webbrowser. This is done in MainListBox_SelectionChanged, where we replace the code that opens the details view:

// Navigate to the new page
NavigationService.Navigate(new Uri("/DetailsPage.xaml?selectedItem=" + MainListBox.SelectedIndex, UriKind.Relative));

with code that opens a browser:

var webBrowserTask = new WebBrowserTask {Uri = ((ItemViewModel) MainListBox.SelectedItem).Uri};
webBrowserTask.Show();

So now, when you tap on an item in the list, the browser will open and go directly to the article mentioned in the rss-feed.

Naturally, you could error handling, offline caching of content, splash screen etc. but that is beyond the scope of this demonstration.

This concludes this example of how to use the standard databound template to create an app that displays latest news (in form of an rss-feed) from a website.

 

This Post Has 4 Comments

  1. great posts in the WP series. waiting on more of them!

    just wondering though, what if those posts are kept continually updated at every set intervals (e.g. 30mins). would the UI auto-update itself? or how would one go about this?

  2. Good question, one that touches on one of the details that I omitted to keeps things as simple as possible, but maybe too simple?
    The ViewModels (MainViewModel and ItemViewModel) both implement INotifyPropertyChanged. That is the reason why the set’er for Public Uri Uri has the line:
    NotifyPropertyChanged("Uri");

    When the control binds to the data in the ViewModel it also subscibes to the PropertyChanged event. So if you update the content of the items in the ViewModel, then those changes will be immediately reflected in the UI.
    If you go to: MainListBox_SelectionChanged and replace
    webBrowserTask.Show();
    with
    App.ViewModel.Items.Remove((ItemViewModel)MainListBox.SelectedItem);
    You will se that the item you click is removed from the UI, when you remove it from the viewmodel.

  3. Hi. I have been trying for a month to get the selected feed to open in a new page instead of the browser.

    You dont happen to know how this is done.

Leave a Reply

Close Menu