WP7 Part 2 – Working with Data

Posted on April 21, 2010 by

This entry is part 2 of 8 in the series Windows Phone 7

This is the second in my series of WP7 articles where I work towards building my first full-featured WP7 application. Part 1 was a �getting started� type of post, where I discussed installation of the tools and stuff you need to get started. This time we tackle the building out of our application by addressing our data needs.

The Application

image For my first WP7 app, I have chosen to build a NerdDinner mobile client � NerdDinner ToGo. The application will allow us to find events that we�re interested in attending, and submit an RSVP for those we want to attend. We�ll also look into adding some social networking integration, perhaps with Twitter, or FourSquare, or similar. Eventually, the final application will use almost, if not all of the most compelling WP7 features such as notification, accelerometer & location sensors as well as all the �normal� stuff you�d expect to find in an application like this. The only challenge I�ve found with using this application as the foundation for this series of posts is that the data in NerdDinner is completely bogus. This is not too bad, but it will create a pretty crazy experience for our end users as they have to navigate through the data other folks have entered in. Maybe we�ll figure out a way to deal with this in future posts, but for now, let�s push on to retrieving data.

Lets start this project off with a new project based on the WP7 List Application template. This template provides more than the plain-�ole WP7 application template � it gives us a foundation for list+details types of applications that we can modify without having to create everything from scratch. The main page will serve up our list of upcoming dinners, and the details page will show us detailed information about a particular dinner. We�ll implement the details page in the next post. For now, let�s focus on getting a list of dinners for our app to start off with.

Retrieving Data from NerdDinner

There are lots of places on the net to get data, and that data comes in lots of different forms. For this application, NerdDinner offers an OData data feed, which is PERFECT for our needs. Although OData is not the only way to get data into a WP7 application, it certainly is a convenient way

For those not familiar with OData, please check out the references at the bottom of this post for more details. There are many great references as well as videos that do a great job of explaining what OData is, and why it�s important.

The OData feed for NerdDinner.com offers two services � one to manage the actual Dinners, and one to manage the RSVPs. Normally, with a WPF or Silverlight application, we could easily add a service reference to this OData endpoint using the �Add Service Reference� feature of Visual Studio. Unfortunately, this feature is currently broken in the CTP tooling, so we have to use some alternate methods. One approach could be to open another instance Visual Studio 2010 and create a new Console application, run the tooling from there, and copy the code into our WP7 project. Another approach is to use the command line tooling supplied with the .NET Framework SDK and use the output in our project. The latter option is the one we�ll go with here.

The command you�ll need is datasvcutil.exe, as found in the .NET Frameworrk SDK. The parameters you need to supply include the endpoint of the service reference, the name of the output file, and a pair of parameters that enable data binding to the results. Once the class is generated, we can simply add it to our project and we�re good to go.

Here�s the command I am using, as run from the Visual Studio 2010 Command Prompt:

datasvcutil /uri:"http://nerddinner.com/Services/OData.svc"
            /dataservicecollection /version:2.0
            /out:nerddinner.cs

The classes that get generated include NerdDinnerEntities, which serves as our primary context for querying and updating entities within the NerdDinner system, and a set of individual data classes that represent entities in the NerdData system. NerdDinnerEntities, as a type of DataServiceContext, allows me to use familiar LINQ queries to retrieve data from NerdDinner � we�ll get to that in a few minutes. For now, let�s create a new folder in our project called �Models� and add this new file to it. You should also change the namespace to fit the [ProjectName].Models namespace to keep things clean. We also need to add a Project Reference to the OData Client OData Client Library for WP7. This library is currently a separate download (see links below), but will eventually be included (and wired up) via the Add Service Reference tooling in the WP7 tools for VS2010.

Once we have this file created, we need to create a Catalog or Repository infrastructure wrapper around it. This wrapper will allow us to decouple the underlying data store from the application, giving us the flexibility to use dependency injection and mocking as our needs dictate. For now, we’re going to start with the most basic infrastructure (an interface that describes the catalog and a single concrete implementation) but will look at expanding this for the future. Our v1 interface is extremely simple:

public interface IDinnerCatalog
{
    void GetDinners();
    event EventHandler<DinnerLoadingEventArgs> 
              DinnerLoadingComplete;
}

The interface currently defines only the GetDinners method (which will return all the dinners supplied by the data source) and an Event Handler for indicating that the data loading is complete. In the future, we’ll expand this to support filter, updating, RSVPs and more. The concrete implementation for this interface is a bit more involved:

public class NerdDinnerCatalog : IDinnerCatalog
{
    public event EventHandler<DinnerLoadingEventArgs> 
	DinnerLoadingComplete;
 
    private Uri theServiceRoot;
    private NerdDinnerEntities theEntities;
 
    public NerdDinnerCatalog()
        : this(new Uri("http://nerddinner.com/Services/OData.svc", 
		   UriKind.Absolute))
    {
    }
 
    public NerdDinnerCatalog(Uri serviceRoot)
    {
        theServiceRoot = serviceRoot;
        theEntities = new NerdDinnerEntities(theServiceRoot);
    }
 
    public void GetDinners()
    {
        var query = from d in theEntities.Dinners
                    orderby d.EventDate descending
                    select d;
        ExecuteQuery(query as DataServiceQuery<Dinner>);
    }
 
    // Call the query asynchronously and update the collection
    void ExecuteQuery(DataServiceQuery<Dinner> qry)
    {
        // Execute the query
        qry.BeginExecute(new AsyncCallback(a =>
        {
            IEnumerable<Dinner> results = qry.EndExecute(a);
 
            if (DinnerLoadingComplete != null)
            {
               DinnerLoadingComplete(this, 
                 new DinnerLoadingEventArgs(results));
            }
        }), null);
    }
}
 
public class DinnerLoadingEventArgs : EventArgs
{
    public IEnumerable<Dinner> Results { get; private set; }
 
    public DinnerLoadingEventArgs(IEnumerable<Dinner> results)
    {
        Results = results;
    }
}

The catalog is created based on a URI that points to our data source, and raises an event when the data loading is complete. The collection of retrieved Dinner objects is returned to the caller via the DinnerLoadingEventArgs. Using events helps decouple the retrieving of data from the main processing thread and allows us to free up the UI while data loading is in progress.

Create the Dinners ViewModel

Now that we have the catalog to help us get our data out of the database, we need to create a ViewModel. The ViewModel is responsible for interactions between the Model and the View. In our case, the DinnersViewModel will utilize the Catalog to fetch Dinner records from the OData data source store them in an instance property, implemented as an ObservableCollection for the view to databind to. As per the MVVM pattern, all interaction with the catalog is managed by the ViewModel – not by the View. In this first phase, we�re going to just do a simple search to return all the dinners, but we’ll expand on this in the future.

public DinnersViewModel(IDinnerCatalog catalog)
{
    theCatalog = catalog;
    theCatalog.DinnerLoadingComplete +=
        new EventHandler<DinnerLoadingEventArgs>(
              Dinners_DinnerLoadingComplete);
}

public void LoadDinners()
{
    theCatalog.GetDinners();
}

void Dinners_DinnerLoadingComplete(
    object sender, DinnerLoadingEventArgs e)
{
    // Fire Event on UI Thread
    View.Dispatcher.BeginInvoke(() =>
        {
            // Clear the list
            theDinners.Clear();

            // Add the new Dinners
            foreach (Dinner d in e.Results) 
                theDinners.Add(d);

            if (LoadComplete != null) 
                LoadComplete(this, null);
        });
}

The LoadDinners method passes on the request for data to the catalog to fetch the appropriate Dinner records. Because the catalog raises an event when the data loading is complete, the ViewModel will register for that event and, once raised, will pull the data into the local collection. That collection, here in the ViewModel, is used by the View for databinding purposes.  This way the , so once it changes, the UI automatically updates. An important note here: you might notice that the DinnerLoadingComplete event handler uses the Dispatch object to update the local Dinner collection on the main UI thread. Don’t forget to do this in your code or you’ll get a runtime error.

Update the UI

Now that our data is coming back from the OData data feed via the catalog, and is populating the ViewModel, it’s time to wrap up by creating the View. In our case, since we used the List Application template, we can utilize most of the code in the MainPage.xaml and just modify it for our needs. First we need to add some code to wire up the ViewModel to the page:

xmlns:vm="clr-namespace:NerdDinnerToGo.ViewModels"

...

<phoneNavigation:PhoneApplicationPage.Resources>
    <vm:DinnersViewModel x:Key="MyViewModel" />
    ...

Notice that we’re declaring access to our ViewModel declaratively instead of in the code. This probably a different approach for you than you’ve done in the past. Using this declarative approach allows us a much richer data binding experience and less code to write and maintain.

Now we need to update the ListBox to wire up to the data dource and to show the data elements that we need from our Dinner objects:

<ListBox x:Name="ListBoxOne" 
         ItemsSource="{Binding Path=Dinners, 
                               Source={StaticResource MyViewModel}}" 
         MouseLeftButtonUp="ListBoxOne_MouseLeftButtonUp" 
         Style="{StaticResource PhoneListBox}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <mpc:ListViewItem 
                 Layout="TextAndDetailsWithIcon" 
                 Text="{Binding Title}" 
                 Details="{Binding EventDate}" 
                 Style="{StaticResource PhoneListBoxItemLayout}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Now that the ViewModel is declared, lets wire it up.

public MainPage()
{
    InitializeComponent();

    SupportedOrientations = SupportedPageOrientation.Portrait;
    Loaded += new RoutedEventHandler(MainPage_Loaded);

    PageTransitionList.Completed += 
         new EventHandler(PageTransitionList_Completed);

    viewModel = this.Resources[&quot;MyViewModel&quot;] 
         as DinnersViewModel;
    viewModel.View = this;
    viewModel.LoadDinners();
}

So there isn’t a lot of code here, but it’s the remaining glue to get things up and running. When the LoadDinners method finishes, the UI will become responsive and the ViewModel will automatically update its Dinner collection with the search results.

image

Summary

In this article I have shown you how to create a basic WP7 application and retrieve data for it. To accomplish that, we implemented the MVVM pattern with a Data Catalog Repository to retrieve our data, maintain it in the ViewModel, and used Silverlight databinding to wire it up to the UI.  In the next post, I�ll show how you can use the page navigation infrastructure to implement a details page that shows additional information about the selected Dinner.

References

Series NavigationDeveloping for Windows Phone 7WP7 Part 3: Navigation

Comments (6)

 

  1. nano says:

    Great post. Thanks!

  2. Chris Koenig says:

    ?
    Thank you for your email. I am currently escorting David Williamson on a whirlwind tour of customers in South Central. During this time, my access to email wil be significantly delayed. Feel free to call or text me at 214-385-5616 if you need to reach me quickly, otherwise I will get back to you as soon as I can.

    Thanks!
    Chris

  3. Edwin Torres says:

    Great post. Thanks!

  4. Chris Koenig says:

    
    Thank you for your email. I am currently escorting David Williamson on a whirlwind tour of customers in South Central. During this time, my access to email wil be significantly delayed. Feel free to call or text me at 214-385-5616 if you need to reach me quickly, otherwise I will get back to you as soon as I can.

    Thanks!
    Chris

  5. Catto says:

    Hey Now Chris,

    Nice Post!!

    Thank 4 the info,
    Catto

  6. Di4beauty says:

    I have turn my phone in today thinking that there wasn’t going to much updating on the WP7. I wished I didn’t. I want my phone back.

    I really like this post but read it to late.