Software Development

My first Windows 8 application

Justin James replaces the sample data sources in his Windows 8 Metro/WinRT application with connections to the Microsoft Research OData source. He says writing the code to use the data is a horrid experience.

Last week, I took you on a tour of Visual Studio 11, installed Team Foundation Server 11, and started a basic Windows 8 Metro/WinRT application from a template. Today, I will replace the sample data sources in the application with connections to the Microsoft Research OData source.

One omission from last week was that I did not show a full-screen view of Visual Studio 2011. Figure A has that view. As you can see, some of the concerns expressed in the comments about the UI being "flat" and difficult to differentiate things are well founded. This is a common complaint from a number of prominent sites and writers, and hopefully Microsoft will decide to put form over function here, especially since Visual Studio 11 isn't a Metro application and does not need to share the Metro look. Figure A

Visual Studio 11 looks like a picture of the Moon... all grey with crater-like icons. (Click the image to enlarge.)

After I use the template to create the basic guts of the application, it is time to get it pulling data from Microsoft Research. I tried to follow Samidip Basu's tutorial for this purpose, but it is not accurate, since it creates classes that depend upon System.Data, which is not accessible from within WinRT. Visual Studio 11's Service Reference wizard won't create proxy classes for OData either.

Let's get this straight: Microsoft puts a ton of work into the Azure Data Market (using OData), gets folks using OData out of LightSwitch and Entity Framework, etc., pushes all sorts of other OData-related technologies, and then does not deliver competent OData support in Visual Studio 11 for Metro/WinRT applications? Come on Microsoft, how do you expect us to take OData seriously when you don't? Speaking of "unsupported," WinRT currently does not have a built-in HtmlDecode function.

So, it is time to try the backdoor route, doing it by hand. I take the SampleDataSource.cs file, and rename it and the classes within to more appropriate names (I replace "Sample" with "MicrosoftResearch"). Next, I take the MicrosoftResearchDataItem class and add a Uri property to store the URI to the actual item. All of my classes are now prepared at a basic level.

The MicrosoftResearchDataSource (nee SampleDataSource) class has hard-coded data. It uses a single data item that it adds a few times to each group. It is easy enough to pull the group information dynamically. The endpoint for the OData service is http://odata.research.microsoft.com/odata.svc, and when you pull that up, you get a list of each available group. I use a WebClient call to download the data. Remember, with WinRT (much like Windows Phone 7), any potentially long-running operation must be done asynchronously. I've already written this code in my Airport Status Checker WP7 application, but there are enough differences between WP7's classes and WinRT's that a direct translation isn't happening. For example, WP7 has the "WebClient" object, which asynchronously makes a request and returns either byte array or a string and fires an event handler when it is done. WinRT has "HttpClient," which uses the new "async" system to make the request, so you use "await" to listen for results. This also necessitates a change in structure a little bit, due to the requirements of async/await.

Writing the code to use the data is a horrid experience. From top to bottom, this is the kind of thing that computers were invented to handle automatically. Instead, the lack of a proper proxy class creator means that I have to write and debug everything by hand, finding out what fields are optional and mandatory, common and not, and coding to that. Honestly, doing this work by hand is absolutely brutal, miserable, and pointless, and it took me an hour or two to go from realizing I needed to write it by hand to having data on the screen. Here is the code I wrote:

public sealed class MicrosoftResearchDataSource

{

private ObservableCollection<MicrosoftResearchDataGroup> _itemGroups = new ObservableCollection<MicrosoftResearchDataGroup>();

public ObservableCollection<MicrosoftResearchDataGroup> ItemGroups

{

get { return this._itemGroups; }

}
private async void GetGroups()

{

{

var downloader = new HttpClient();

downloader.MaxResponseContentBufferSize = int.MaxValue;

var groupXml = await downloader.GetStringAsync("http://odata.research.microsoft.com/odata.svc/");

var groupData = XDocument.Parse(groupXml);

var workspaceName = XName.Get("workspace", "http://www.w3.org/2007/app");

var titleName = XName.Get("title", "http://www.w3.org/2005/Atom");

var collectionName = XName.Get("collection", "http://www.w3.org/2007/app");

var entryName = XName.Get("entry", "http://www.w3.org/2005/Atom");

var contentName = XName.Get("content", "http://www.w3.org/2005/Atom");

var propertiesName = XName.Get("properties", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");

var idName = XName.Get("id", "http://www.w3.org/2005/Atom");

var summaryName = XName.Get("summary", "http://www.w3.org/2005/Atom");

var nameName = XName.Get("Name", "http://schemas.microsoft.com/ado/2007/08/dataservices");

var descriptionName = XName.Get("Description", "http://schemas.microsoft.com/ado/2007/08/dataservices");

var urlName = XName.Get("Url", "http://schemas.microsoft.com/ado/2007/08/dataservices");

XElement summaryElement;

XElement nameElement;

XElement descriptionElement;

XElement urlElement;
foreach (var collection in groupData.Root.Element(workspaceName).Elements())

{

try

{

if (collection.Name == collectionName)

{

var groupName = collection.Element(titleName).Value;

var group = new MicrosoftResearchDataGroup(groupName, groupName, "", "", "");
var itemsXmlStream = await downloader.GetStreamAsync("http://odata.research.microsoft.com/odata.svc/" + collection.Attribute("href").Value);
var itemData = XDocument.Load(itemsXmlStream);
foreach (var item in itemData.Root.Elements())
{
if (item.Name == entryName)

{

var properties = item.Element(contentName).Element(propertiesName);

try

{

summaryElement = item.Element(summaryName) ?? new XElement("summary");

nameElement = properties.Element(nameName) ?? new XElement("name");

descriptionElement = properties.Element(descriptionName) ?? new XElement("decription");

urlElement = properties.Element(urlName) ?? new XElement("Url");

var dataItem = new MicrosoftResearchDataItem(item.Element(idName).Value, item.Element(titleName).Value, summaryElement.Value, "", nameElement.Value, descriptionElement.Value, urlElement.Value, group);

group.Items.Add(dataItem);

}

catch (Exception ex)

{
}

}

}
this._itemGroups.Add(group);

}

}

catch (XmlException ex)

{
}
}

Once I get it working, I tweak the XAML slightly, primarily to get rid of the image (since there are no images to use in the data) and to add the URLs for the items. I also discover that the XAML contained references to the original SampleDataSource class (even though "Rename" supposedly checks all files for it) for design-time data. I try to change it to my new data source class, but this was an absolutely wretched process because it was continuously attempting to instantiate my data source class; this data source needs to pull a ton of data off the network and parse it. As a result, I opt to make a "SampleMicrosoftResearchDataSource" that mocks up the MicrosoftResearchDataSource (and have it use some hard-coded content) and use it for the design time display. Incidentally, the call that instantiates/binds the data to the application at runtime is in App.xaml.cs; it creates the MicrosoftResearchDataSource object and passes it to the navigation method of the root frame. That is fairly ugly, it is not very intuitive, and it is difficult to discover where exactly data is coming from, which complicates a gripe I've had about XAML and binding for a long time.

The application works fine. Figure B, for instance, shows one of the item views (I need to strip the HTML out of the text). I like the controls on the right and left to allow paging, though for a touch device, having "Back" and "Next" on each side like the paging buttons on a Kindle would probably be better for usage (though less intuitive). I really feel like I got "something for nearly nothing" with the application template, which is rare; I typically feel that starting from scratch is the best way to make applications because the templates never seem useful. Figure B

Item view (Click the image to enlarge.)

The biggest problem with this application in its current state is performance. It is an absolute dog, and the reason is clear: the source data was many, many megabytes of XML that has been turned into a data structure in memory to be navigated, and at times, thrown onto a page all at once.

The solution is obvious: It needs to be able to load only a handful of items at a time, possibly even a few hundred or so. We see this on mobile devices all the time to save bandwidth at the expense of time. Doing a pre-fetch or an on-demand fetch of the next one 100 items could make sense, but on the surface, it is a pretty complicated technique. It is possible that I missed the boat on a useful option of the controls that enable this; I will do more digging and hopefully come up with a good option for this. Alternatively, maybe I just need to do something really simple, like hook onto the "yield" behavior of the collection classes for the data, and only load items if they aren't loaded, and then load them in batched from a cached copy of the file. I also suspect that removing the URL path entirely from the data objects and editing the UI templates to not try to show images will be a huge help (think of all of those instances of the blank, default images being loaded!). It is going to take some time for me to figure out how to address this performance question.

My next goal for this project is to implement search and use the Contracts to expose the application as a search provider to Windows 8. After that, I will work on tweaking the UI more, since it is not meeting the needs of the application right now.

J.Ja

Keep your engineering skills up to date by signing up for TechRepublic's free Software Engineer newsletter, delivered each Tuesday.

About

Justin James is the Lead Architect for Conigent.

6 comments
Ron_007
Ron_007

Too bad it has to present a negative view, but if that is your experience, it is worth knowing. I'll second your observation about the "flat" UI. It is a seemingly small thing, but since we are interating with the UI all day long, mousing over it it is significant. It is an "improvement" they made in the ribbon with Office 2010. Compare any Office 2007 app to it's 2010 sibling. In 2007, the edges of the buttons are clearly defined, in 2010 that definition is gone. I hate it because you no longer know where to click just by looking, you actually have to mouse over the button to see when it gets focus. I hate it. If they wanted to make this alleged "improvement", I wish they would give us the option of selectin 2007 color scheme too. I think it would be interesting to see how many people selected that option over the 2010 color scheme.

TechRepublic
TechRepublic

I am personally sick and tired of MS coming up with so called "inovations" which do nothing more than stimulate their bottom line. If that is the type of programming a company wants to be associated with then good luck. I don't know if it is dollar motivated or if someone with vision lost it but I see MS now going the way of Novell. I am going to learn from the past and sit this one out. MS Win8 is the failure version of their trend of every other version is useful scheme. I won't waste my time or my customers with this. They may need to unify their OS but the interface should be according to the hardware. One size does not fit all.

conrad
conrad

I'm starting to notice that every article I read on this site related to Microsoft is negative....

Justin James
Justin James

... that something that is a 30 second task in Visual Studio 2010 should take me hours in Visual Studio 11? While I understand that VS11 is currently a "beta", I found it quite surprising that this piece of functionality is completely dead in the water... especially when it is critical to developing the Metro applications that Microsoft so badly wants us to have prepped and ready for the Windows 8 launch! J.Ja

IAmFabulous
IAmFabulous

not very responsible writing imo. Takes focus away from a lot of positive experiences, and people considering a move might think otherwise because of such articles.

atoms
atoms

This is the kind of information that is hugely valuable. It isn't the sort of thing you see in a press release or a sales pitch. We need to know the pitfalls before we waste our own valuable time. Great job Justin!

Editor's Picks