Saturday, March 3, 2012

Windows 8 Consumer Preview & Visual Studio 2011


Windows 8 Beta is here. And it’s fantastic. I’m not just saying it because I’m a Microsoftie, or because I’m getting paid for that, or anything like that. This is (so far) my honest sincere opinion. Why, may you ask ? Just play with it for a little while and you’ll know. The Start menu is just beautiful, feels like a smartphone with no capacity restrictions. I really like the corner gestures : lower left for the start screen, upper left for last open app AND list of all open apps, upper and lower right for bringing up the charms. And I love the new ability to close an app by grabbing the top “edge” of it and literally bringing it down through the bottom of the screen. Feels so good to do that. And the crazy thing is, it all works just as well with touch AND mouse & keyboard. In short, love it.


Now for the serious stuff : I have quite a few apps I developed on the Developer Preview version. Bad news : so much has changed in Windows (winRT) that they just no longer run in the new version. Just try to open an devprev app with VS 11 consprev : total fail!

So, let’s roll up our sleeves and get to work, there’s a lot of stuff to catch up with to understand the breaking changes. It’s all listed in this document, have fun reading it… As far as I’m concerned, I decided to read it on an as-needed basis. So where do I start in migrating my apps ? I have this sample app I wrote using the Grid Application VS template in the old world. Tried to open it in the new vs, no way. So I followed the basic guideline that says, create a new project and then '”import” your code. I created a project using the new Grid metro style app template (C# XAML) :


That created a GroupedItemsPage, a GroupDetailPage, and an ItemDetailPage for me. New thing : these pages inherit from a base LayoutAwarePage which handles the layout change events associated with the visual states such as Filled vs Snap or Portrait vs Landscape. Also has some infrastructure code to facilitate data binding in our custom pages. Anyway, if you try to bring in a page from an existing devprev app, build will fail as a lot of APIs have changed. For example, classes that have the word ‘Layout’ in their names have been renamed to use ‘View’ instead, so ApplicationLayout has become ApplicationView. That’s just an example. Since the old pages contained the layout change code, it’s really a pain to try to update them. So the best approach is to recreate the page, and bring in the custom XAML that you’ve created to build the UI. Doing so, it wasn’t too bad porting the app – of course I’m talking about a simple app using the Grid template and some data binding.

Speaking of the devil, using data binding is a bit different as well. If you look at the new Grid project template, the code-behind files use an object called DefaultViewModel. If yo examine the base LayoutAwarePage, you’ll see that DefaultViewModel refers to an ObservableDictionary<string,object>. What the heck is that, I hear you ask ? It’s just a convenient way of storing a simple view model. Say you have data in the form of a list of groups of widgets, and you want the grouped page to show the groups, then the group details page to show the content of a group, that is a sub-list of widgets, and then a detail page that shows data for a specific widget.  You can store the list of groups in the dictionary under a string such as “WidgetGroups”. Then in your XAML you can define a CollectionViewSource pointing to your list like this :

   1: <CollectionViewSource
   2:     Source="{Binding WidgetGroups}"
   3:     IsSourceGrouped="true"
   4:     ItemsPath="Widgets"/>

‘Widgets’ is the name of the list within a group, so WidgetGroups is a list of groups that each contains a list of Widgets. Now where does that all get set, you scream ? It all starts in app.xaml in the OnLaunched event, where this code is called :

   1: rootFrame.Navigate(typeof(GroupedItemsPage),myWidgetGroups);

As you guessed, this will bring up the GroupedItemsPage – notice the Frame.Navigate() method has changed, it now accepts a type as the first param – and pass to it the group list. Now, in the GroupedItemsPage itself, in the OnNavigatedTo() method you do something like this :

   1: protected override void OnNavigatedTo(NavigationEventArgs e)
   2: {
   3:     this.DefaultViewModel["WidgetGroups"] = e.Parameter;            
   4: }

Where e.Parameter is the myWidgetGroups object you set in the Navigate call. It’s now stored in the DefaultViewModel dictionary under the “WidgetGroups” key, and the dictionary is the datacontext for the page, so you’re all set!

You do the same to pass data to your other pages : when something is selected for example, you call Navigate(typeof(myotherpagetype), theSelectedStuff) and in the other page, you retrieve it in the OnNavigatedTo() method and add it to the DefaultViewModel dictionary under a different key. So what’s the purpose of this new Dictionary ? Being an ObservableDictionary, it has the capability of notifying the UI when its contents are updated. So there you have it, a new INotifyCollectionChanged copycat, and a super convenient one too.

So this was a quick example of how to port a metro app written in XAML under devprev to the new consprev version. I’ll be doing quite a bit of that in the days to come, as I’m refreshing a couple of new courses on win8 Metro, so I’ll keep you posted!

No comments:

Post a Comment