This is the second post in a series about creating a Universal App for Windows. Today we are going to make sure that our app shows some actual data.

In the previous post I wrote that the app will show exchange rates data from real banks. Well, this is the main challenge actually. As far as I know there is no public API that exposes such information. So I’m going to extract it from HTML pages. I’m pretty sure that the app might never be approved in the Windows Store, but I have no intention to submit it there anyway.

Data Source

I’m going to use this page as a data source: http://quote.rbc.ru/cash/. It updates frequently and it’s stable enough to parse it. I can’t guarantee that they won’t change the layout or html code, but this data source should be enough for my little project.

Data Access Layer Skeleton

Here is what I ended up disigning:

DAL Class Diagram

Basically, in my case the main purpose of the Data Access Layer (DAL) is to retrieve a list of currency exchange quotes from the data source.

RbcQuoteService will be the main entry point to DAL, its GetExchangeRates method will be used by other components of the system.

QuoteDataProvider with the help of QueryBuilder will retrieve raw data from the data source and return it to RbcQuoteService class.

There is one additional class mentioned on the diagram - MockWuoteDataProvider, it’s going to be used in Tests project. This is when a quote complex class structure starts paying off - IoC and dependency injection allows to test code in RbcQuoteService just by passing a test-version of IQuoteDataProvider.

I’m not going to put code of these classes here, instead I’ll give you a link to github where you can examine these changes and comment if you’d like.

By now there is just a skeleton of DAL and the first unit-test (which of course fails at the moment):

[TestMethod]
public void TestResultsParsed()
{
  var queryBuilder = new QueryBuilder { City = City.StPete, Currency = Currency.USDRUB };
  var quoteProvider = new MockQuoteDataProvider { QueryBuilder = queryBuilder };
  var service = new QS(quoteProvider);

  var result = service.GetExchangeRates();

  var exchangeDatas = result as ExchangeData[] ?? result.ToArray();
  Assert.IsTrue(exchangeDatas.Any());

  foreach (var item in exchangeDatas)
  {
    Assert.IsNotNull(item.Name);
    Assert.IsTrue(item.BuyRate.HasValue || item.SellRate.HasValue);
    Assert.IsFalse(item.DateCreated == DateTime.MinValue);
  }
}

From now on I’m going to write code only to fix failing tests.

Fixing DAL

In order to fix my failing test I’m going to need some test datasource. Since I’m parsing a website my data source is plain HTML code. I’ll put a sample file my test project and will load its contents in MockQuoteDataProvider.

To parse HTML code I’ve added HtmlAgilityPack as a nuget package. It is supported across all our platforms, and it’s not that big not to use it.

Other than that, there is not much interesting here except that this stuff can suck you into such a flow so you might forget to sleep! I realized that at 2am after 6 hours of coding non-stop and it was awesome! :)

The results are as usual in github commit - fixing DAL in one shot

Making things work in UI

There is a great sample created by Microsoft: XAML ListView and GridView essentials, I’m going to use it to build my page with a list.

<Page
  ...
  xmlns:controls="using:CashQuotes.Controls">

  ...

  <Page.Resources>
      <DataTemplate x:Key="GridItemControlTemplate">
          <controls:ItemViewer/>
      </DataTemplate>
      <DataTemplate x:Key="GridHeaderControlTemplate">
          <controls:ItemHeader />
      </DataTemplate>
  </Page.Resources>
      
  ...

  <GridView x:Name="ItemGridView"
    Background="{StaticResource ApplicationPageBackgroundThemeBrush}" 
    ItemTemplate="{StaticResource GridItemControlTemplate}" 
    HeaderTemplate="{StaticResource GridHeaderControlTemplate}"
    ...
    ContainerContentChanging="ItemGridView_ContainerContentChanging" />

 ...

There are 2 new User Controls here: ItemViewer and ItemHeader. I defined them in the Shared project so that they are available in both Windows and Phone versions. If I ever need to extend them in only desktop or mobile version, I’ll create a partial class and put it into the respective project.

There is one pretty cool technique used here - take a look at ItemGridView_ContainerContentChanging method in QuoteListPage class:

private void ItemGridView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
  var iv = args.ItemContainer.ContentTemplateRoot as ItemViewer;

  if (args.InRecycleQueue)
  {
    iv.ClearData();
  }
  else if (args.Phase == 0)
  {
    iv.ShowPlaceholder(args.Item as ExchangeData);

    // Register for async callback to visualize Title asynchronously
    args.RegisterUpdateCallback(ContainerContentChangingDelegate);
  }
  else if (args.Phase == 1)
  {
    iv.ShowRates();
    args.RegisterUpdateCallback(ContainerContentChangingDelegate);
  }
  else if (args.Phase == 2)
  {
    iv.ShowName();
    iv.ShowDistance();
  }

  // For imporved performance, set Handled to true since app is visualizing the data item
  args.Handled = true;
}

It will visualize the data in grid in multiple iterations. User will see placeholders first, then the app will try to load names, rates and finally distance when it’s calculated. All this will be done asynchronously, user will be able to interact with the grid right after the app is loaded, no freezing UI or modal “loading…” notice.

Results

Right now my app is finally able to show real data! Here is what I have right now:

The first page showing real data

(I rotated the screen to better fit this page)

You can scroll up and down, but no details-view yet. The full source can be found in Github under week2 tag.

Stay tuned!