I wrote about my adventures in converting a Web application (BusterNews.com) to WPF in a previous post. In that article, I briefly mentioned that I wanted to set the new application apart from its web counterpart by presenting feed items in a contiguous list instead of the ‘paged’ approach of a web application. The main challenge in accomplishing this goal was that the application’s data source is a web service (no data is cached on the client), and so providing this feature was not as straightforward as using a built-in WPF feature. Fortunately, it was as straightforward as utilizing the Xceed DataGrid’s data virtualization capabilities (available on the Pro version).
Before I continue, let me point out that Xceed provides a far more detailed sample project (which was the basis of my solution) in their documentation. My focus in this post is the technique I used for integrating the web service as a data source of the data grid; the feature set I use is only a small subset of the data virtualization capabilities of the datagrid control.
Back to the problem: I wanted to present feed items such that a user can navigate anywhere in the list just as they would in a desktop application like Outlook. The problem was that certain feeds may have thousands of items and bringing this data back from a web service may be very costly in terms of bandwidth and perform poorly from the user experience perspective. The image below shows a sample of this case --- news feeds like MSNBC may contain thousands of items over a period of two weeks because it updates many times a day.

My solution consisted of two main parts:
- Setting-up the datagrid for virtualization
- Setting up web services to serve the data that the datagrid needs
Setting up the DataGrid
Setting up the DataGrid requires configuring it with a DataGridVirtualizingCollectionView data source and setting event handlers for the specified data source.
The following XAML code block shows part of the declaration that includes binding to the datasource:
The ItemsSource property is bound to a ReaderFeedItems dependency property of the page which is a DataGridVirtualizingCollectionView type. The property is set up as follows:
The code above shows the following:
- ReaderFeedItems is set to a DataGridVirtualizingCollectionView with a page size (m_feedItemsPageSize) and a maximum realized item count (m_feedItemsMaxRealizedItemCount). This sets up the datagrid with a special collection view that knows how to perform data virtualization. The collection view is configured with settings for managing the paging of data items and memory.
- Handlers are set for the different data virtualization events:
- The QueryItemCount event occurs when the datagrid needs to know how many items are in the data source.
- The QueryItems event occurs when the datagrid needs a page of data.
- The AbortQueryItems event occurs when the request for a page of data is cancelled.
The event handlers look something like this:
The code above shows the following:
- ReaderFeedItems_QueryItemCount calls a web service to get the feed items count for the currently selected feed source.
- ReaderFeedItems_QueryItems makes an asynchronous call to a web service for the set of data requested by the data grid. When the asynchronous call is successfully completed, the data returned is passed back to the datagrid. This is shown in the following event handler code:
The solution is generally as simple as that.
One significant implementation note I would like to make is that I had to cache the datasets (using ASP .Net session state) on the server side to keep return values for queries consistent throughout a user session. Without this, data virtualization will fail once the data changes as the application currently has no mechanism for getting notified when new feed items for the current dataset have come in.
posted @ Monday, March 30, 2009 12:45 AM