Session 3 of the WinRT Development Class – App Lifecycle and Navigation

WinRTWebBannerSmall_JPEG

What an excellent session! I know it’s been a little over a week, but I’m very grateful to all those who attended! For those of you who were not able to attend we have a video of the session! Please find the class resources and link to the video below.

Session 3 Resources

Overview of Sessions

The links below lead you to Meetup Events where you can RSVP. We look forward to seeing you at our next session!

1. Introductory Lecture (Nov 27th by Danny & Kevin)
2. Introduction to XAML and WinRT’s powerful Control Framework; (Dec 4th by Danny & Kevin Click here for the video recording)
3. Page-Navigation Model and Application Lifecycle (Jan 8th by Danny Click here for the video recording)
4. Fundamentals (Async/Await, WinRT API, Security) (Jan 15th by Kevin Click here for the video recording)
5. Settings and Search Contract (Jan 28th by Danny)
6. Share Contract (Feb 4th by Kevin)
7. Live Tiles and Background Tasks (March 18th by Kevin)
8. Orientation Handling and Proximity using Near Field Communication (NFC) (March 25th by Danny)
9. Introduction to ModelViewViewModel (MVVM) (April 8th by Danny)
10. InterKnowlogy’s WinRT MVVM Framework Session Part I/II(April 22nd by Kevin)
11. InterKnowlogy’s WinRT MVVM Framework Session Part II/II(May 6th by Danny)
12. Presentation of Hackathon Results + Certificate/Prize Giveaway(May 22nd by Danny and Kevin)

Session 1 & 2 of the WinRT Development Class – Introduction, XAML, and WinRT’s Control Framework

WinRTWebBannerSmall_JPEG

 

The first two sessions of the WinRT Development class were a great introduction to what Windows 8 WinRT development really is and to XAML development. We’re very excited about the future sessions and hope every developer will come learn with us about developing WinRT apps!

Session 1 Resources

Session 2 Resources

 

Overview of Sessions

The links below lead you to Meetup Events where you can RSVP. We look forward to seeing you at our next session!

1. Introductory Lecture (Nov 27th by Danny & Kevin)
2. Introduction to XAML and WinRT’s powerful Control Framework; (Dec 4th by Danny & Kevin Click here for the video recording)
3. Page-Navigation Model and Application Lifecycle (Jan 8th by Danny)
4. Fundamentals (Async/Await, WinRT API, Security) (Jan 15th by Kevin)
5. Settings and Search Contract (Jan 28th by Danny)
6. Share Contract (Feb 4th by Kevin)
7. Live Tiles and Background Tasks (March 18th by Kevin)
8. Orientation Handling and Proximity using Near Field Communication (NFC) (March 25th by Danny)
9. Introduction to ModelViewViewModel (MVVM) (April 8th by Danny)
10. InterKnowlogy’s WinRT MVVM Framework Session Part I/II(April 22nd by Kevin)
11. InterKnowlogy’s WinRT MVVM Framework Session Part II/II(May 6th by Danny)
12. Presentation of Hackathon Results + Certificate/Prize Giveaway(May 22nd by Danny and Kevin)

WinRT and “Fun” (ok, PAIN) With a Grouped GridView

I’ve seen examples of the new WinRT GridView in a bunch of the samples and demos from Microsoft, but had never used the control for my own app before.  During the past couple weeks of RECESS, I’ve been writing a Ping Pong results tracking app with a couple co-workers, and set out to use the GridView in grouped mode.  (Yes, PING PONG – we got a new table at the office a few months ago, and the competition is getting intense. We need to start recording these results!)

As with almost all demos from Microsoft, the app uses some not-so-real-world techniques: manipulating UI from code-behind, and creating the data source from in-memory data stores.  I’m using an MVVM design and getting real data from a real (MongoDB backed) web service.  This is just a quick post on what did and did not work for me when learning the GridView via trial and error.

For all the code below, I’m using a simple hierarchical data structure:  Teams that contain a collection Players.

Bind GridView Directly to a VM Collection – Does Not Work

    Teams = DataModel.GetTeams();
    <GridView ItemsSource="{Binding Path=Teams}"
              Margin="5"
              >

This works (well, it displays the outermost collection of objects, but doesn’t do any grouping).  For the GridView to use grouped data, you must provide a CollectionViewSource with IsSourceGrouped set to true.  I can’t find anywhere that you can tell the GridView directly that it’s ItemsSource contains grouped data.

Create CollectionViewSource Manually – Does Not Work

I’ve seen the CollectionViewSource created as a resource in the UI View in all the samples, but since I’m using MVVM, I want to bind to VM properties. I try to create and store a CollectionViewSource in the VM and bind straight to it.

    Teams = DataModel.GetTeams();
	
    CVS = new CollectionViewSource
    {
        Source = Teams,
        IsSourceGrouped = true,
    };
    <GridView ItemsSource="{Binding Path=CVS}"
              Margin="50"
            >

I get an ArgumentException in the CollectionViewSource property setter (via the NotifyPropertyChanged event).  This occurs when the GridView that is bound to that CVS doesn’t like what it sees.

Bind Resource to VM Property – Works

Here’s a compromise, I never realized you could do this.  Declare the CollectionViewSource in XAML (set IsSourceGrouped), but bind it’s source to the VM property. Notice I’m also able to set ItemsPath to describe what property in the parent type holds the children.

    <Page.Resources>
        <CollectionViewSource x:Key="GroupedData" 
                              IsSourceGrouped="True"
                              Source="{Binding Teams}"
                              ItemsPath="Players"
                              />
    </Page.Resources>
	
    <GridView ItemsSource="{Binding Source={StaticResource GroupedData}}"
                Margin="50"
                SelectionMode="Single"
                >
    Teams = DataModel.GetTeams();

Use a LINQ Group By Directly – Works

All the samples I’ve seen use a LINQ query to fetch grouped results, and then push those results into a custom data structure.  I originally thought you had to do this for the GridView to understand the grouping, but it’s not required. I see a bunch of discussions where the collection must implement a certain interface, or where you must write your own wrapper classes that derive from IGrouping, etc. but those don’t seem to be required either.

Here I’m setting my grouped LINQ query as the property that the GridView will bind to (again via the CollectionViewSource resource).  Notice a couple things:

  • I’m unnecessarily using LINQ to group my results even though my data is already in a hierarchy (this is just to prove a point)
  • You can project the LINQ results into either concrete types or anonymous types. The GridView, as with any other WinRT UI element, is happy to bind to anonymous types (I remember this was a problem in early versions of WinRT, but seems to be fixed now)
  • The LINQ group container is a string/collection dictionary (Team.Name to Teams in my case), so I cheat a little and call .First() to get to the one and only Team in each group, since I know I have unique team names.
    Teams = DataModel.GetTeams();
    GroupedLinq = from team in Teams
                    group team by team.Name
                        into g
                        //select new Team
                        //{
                        //	Name = g.Key,
                        //	Players = new List<Player>( g.First().Players )
                        //};
                        select new
                        {
                            Name = g.Key,
                            Players = g.First().Players
                        };
    <CollectionViewSource x:Key="GroupedLinqData" 
                            IsSourceGrouped="True"
                            Source="{Binding GroupedLinq}"
                            ItemsPath="Players"
                            />

    <GridView ItemsSource="{Binding Source={StaticResource GroupedLinqData}}"
                Margin="50"
                SelectionMode="Single"
                >
        <GridView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=Name}"
                            Width="200"
                            Margin="5"
                            />
            </DataTemplate>
        </GridView.ItemTemplate>

        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}"
                                    FontSize="36"
                                    />
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>

                <GroupStyle.Panel>
                    <ItemsPanelTemplate>
                        <VariableSizedWrapGrid Orientation="Vertical" Height="200" />
                    </ItemsPanelTemplate>
                </GroupStyle.Panel>
            </GroupStyle>
        </GridView.GroupStyle>

    </GridView>

Summary

I hope these examples help you get through the learning curve of the GridView faster than I did.

 
 

Accessing Dependency Property (DP) Changed in WinRT

With the release of Windows 8 and WinRT, I began the process, during RECESS, of porting an existing app we’d created for the Microsoft Surface (the team that is now called “Pixel Sense”) to be a Windows Store application. The application followed more of an MVC (Model View Controller) approach, rather than MVVM (Model View ViewModel), so there we a number of controls that subscribed to the DataContext and Visibility changed events in their code behind, which don’t exist in WinRT.

WinRT (Windows Store) applications seem to have many of the same limitations that Silverlight had, compared to WPF, and rather than rewrite the parts of the application to try and avoid needing to know when these DPs changed, I came up with a simple framework to register for a callback when a specified DP changed.

First Solution

The way to get around this issue was actually really straight forward. In each control, I created and registered a DP for each DP I wanted a change notification from (ie. DataContextEx, VisibilityEx, etc…).

public static readonly DependencyProperty DataContextExProperty =
		  DependencyProperty.Register( "DataContextEx", typeof( object ), typeof(DemoControl ),
			new PropertyMetadata( null, OnDataContextExChanged ) );

public object DataContextEx
{
	get { return (object)GetValue( DataContextExProperty ); }
	set { SetValue( DataContextExProperty, value ); }
}

private static void OnDataContextExChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
	( (DemoControl)d ).OnDataContextExChanged( e );
}

private void OnDataContextExChanged( DependencyPropertyChangedEventArgs e )
{
	//Handle the change
}

Then, in the control’s constructor, I bound the created DP(s) to the related DP I wanted to know had changed. With this binding, whenever the source DP (ie. DataContext, Visibility, etc…) changed it would cause the “extension” DP to change and that would call the changed handler I registered when creating the DP.

var binding = new Binding
			{
				Path = new PropertyPath("DataContext"),
				RelativeSource = new RelativeSource
								{
									 Mode = RelativeSourceMode.Self
								}
			};
SetBinding(DataContextExProperty, binding);

With this I had all that I needed. However, I hated the idea of having to rewrite this code on every control that I needed the notification on. So I decided to create a framework to allow me to register for a changed callback on any FrameworkElement.

Framework

I decided to go the route of creating a FrameworkElement extension method called RegisterDependencyPropertyChanged that takes a lambda expression for the property to bind to and a callback for when that property changes.

this.RegisterDependencyPropertyChanged( () => DataContext, DataContextChangedHandler );

The extension then calls RegisterDependencyPropertyBinding on FrameworkElementAttachedProperties. FrameworkElementAttachedProperties is an internal class that holds the functionality to create and register an Attached DP for each type of DP (ie. DataContext, IsHitTestVisible, Visibility, etc..) the user desires a callback for and bind that Attached DP to the DP (using the same process defined under First Solution. Then whenever that value changes it attempts to find a callback registered for it, and if one is found, calls the registered callback with the DependencyPropertyChangedEventArgs provided.

Attached DPs are only able to be bound to one property of an object at a time (but can be bound to the same property of multiple objects). This is why an Attached DP is created and registered for each DP of a control as there may be a case where a change callback is registered for more than one property of that control. Therefore whenever FrameworkElementAttachedProperties.RegisterDependencyPropertyBinding is called it calls GetNextUnusedAttachedPropertyForFrameworkElement. This either grabs an existing Attached DP registered for that property, or it will create and register a new one and return it.

private static DependencyProperty GetNextUnusedAttachedPropertyForFrameworkElement( string propertyName )
{
	if ( !_staticExtensionDPs.ContainsKey( propertyName ) )
	{
		var unusedDependencyProperty = DependencyProperty.RegisterAttached( _extensionDPsNamePrefix + "_" + propertyName,
													   typeof( object ),
													   typeof( FrameworkElementAttachedProperties ),
													   new PropertyMetadata( null, DependencyPropertyExPropertyChanged ) );
		_staticExtensionDPs.Add( propertyName, unusedDependencyProperty );
	}
	
	return _staticExtensionDPs[propertyName];
}

The registered callbacks are stored in the DependencyPropertyCallbacks Attached DP on FrameworkElementAttachedProperties. By storing the callbacks in the Attached DP, when the control that has registered is unloaded, it can be collected by the Garbage Collector and there aren’t memory leaks.

Conclusion

I tend to prefer the MVVM approach, but there are cases when constraints dictate that a different approach is used. This is a nice little addition for when that occurs. Here is a demo solution containing the framework (FrameworkElementExtension.cs) and an example of how to use it.

Informant Architecture

With the release of Informant v0.1.5.0 today I wanted to take a minute and talk about some of the changes and challenges I faced with this iteration. Let me first tell you what my goal was with this iteration. I wanted to create a single code base that could be reused in the Windows Service world as well as in WPF4, Silverlight 4, and Windows Phone 7. The challenge was finding which kind of class library can be shared with other kinds of applications. I discovered that Silverlight 3 was the appropriate base library type to use. Any .NET solution can reference SL3 libraries. I hoped to be able to make all of my model objects in SL3 assemblies and share them across all applications. However, I ran into some show stoppers in namespace conflicts. The model objects would be used in WCF therefore they needed to have DataContract and DataMemeber attributes applied to them. The namespace System.Runtime.Serialization cannot be shared between SL3 and WPF4. I got the following exception when I tried this: “Could not load file or assembly ‘System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e’ or one of its dependencies. The system cannot find the file specified.” WPF4 does not understand and is not compatible with this version of the SL3 framework. Super big bummer! This meant that I could only use Interfaces to enforce my model object APIs. Since I wanted consistency this is exactly what I did. Only one SL3 library is shared between all of the UI applications and the Windows Service.

The next hurdle was handling a WCF service reference that would work in all scenarios. I found that this was also not possible, or rather was not ideal for my situation. I wanted my WPF4 application to be very rich and have have duplex channels which are not supported in SL3/4 or Wp7. This meant that every framework had to have it’s own non-reusable reference to the service. These references live in the DataProviders.[Framework] assemblies. Even though I know that the model objects coming from the service are implementing the Interfaces defined in the shared library, I cannot treat these objects as those Interfaces when they come out of the service. I must be able to do this in order for my UI, ViewModels, and other DataProvider dependent assemblies to be shared across frameworks. To overcome this I made a partial class for each model object coming from the service and had the partial I made implement the correct Interface. This caused two problems for me. First, the Interfaces were using IEnumerable<T> which is not supported in WCF. The models from WCF all use List<T> when they come across the wire. In order to solve this I had to tell WCF to change the names of the IEnumerable<T> properties when they were sent across the wire and I had to make each IEnumerable<T> property in the partial I made use the List<T> property from the WCF partial class as the backing field. This was preferred over changing the Interfaces to enforce desired behavior. Second, there was an error that said the WCF partial and the partial I made had difference base classes after I implemented the Interface. This was so very confusing, and it took me a while to figure out. Turns out Visual Studio 2010 (and perhaps prior versions) specify each model as inheriting from object.

public partial class Contact: object

This behavior is unnecessary and redundant since every object in C# already inherits from object by default. I had to go through the Auto Generated code and remove all explicit inheritance from object. After I did this the application compiled just fine. Strangely enough, now whenever I update my service reference the explicit inheritance is added back in, but does not cause an error as it did the first time. While I’d love to understand what exactly was going on with the error, it seems to have resolved and is no longer causing me issues so I’ve stopped looking into it.

The UI presented the final difficulty. We use DelegateCommands all over in our ViewModels here at InterKnowlogy and I wanted to do the same in my VMs. The problem is the underlying implementation of the DelegateCommand class, and other classes, are so different that a VM specifically designed for each framework must exist. Much of the core functionality of each VM can be shared in a base VM but each framework must still have a specific VM implementation. The idea that VMs can be reused without modification is false, but a good deal of each VM can be shared, and that’s exactly what I took advantage of.

With all of that said and done I now have a working version of Informant for WPF4 referencing a Windows Service that is installed on the same machine. The service is required so users can close the application and leave their computer on and Informant will still send all of the desired SMS messages. The Wp7.5 (Mango) version is next on my plate. This version will require me to refactor the Windows Service to support a RESTful API. The service will also need to be hosted on a publicly accessible server. My goal is to enable Wp7 users to be able to send SMS messages to their contacts and contact groups. A SL5 version will then be next available on the same server as the RESTful service.

The ability to reference SL3 libraries in the different .NET frameworks has greatly decreased the amount of work required to develop a framework specific application that fulfills the same purpose. It’s quite amazing and awesome. However, a small word of caution should be made known. The new Windows 8 WinRT framework is NOT compatible with this pattern. Each library must be a WinRT library compiled against WinRT. So I will not be able to reuse the libraries, as is, in Windows 8 WinRT. This is a huge bummer, but makes sense as I’ve learned more about what WinRT really is.

Kinect in Windows 8 on .NET Rocks

My coworker Danny Warren and I recorded a .NET Rocks session a couple weeks that just went live tonight.  We discuss how we got a Windows 8 / WinRT application to communicate with the Microsoft Kinect.  I blogged about how we pulled that off here, but check out the podcast to hear it first hand.

.NET Rocks show #714 – Dan Hanan and Danny Warren Mix Kinect and Metro

Crazy WinRT XAML Bug in Windows 8 Developer Preview

I’ve been playing with the developer preview release of Windows 8 that we got from //BUILD/.  Everyday, we find more and more “issues” that are either just straight up bugs, things that are not implemented yet, or maybe even issues that won’t be resolved because WinRT is “just different”.  This one was especially “fun” to track down – and when we did, we couldn’t believe the issue.

Start with a simple WinRT application in Visual Studio 11.  Add a class library project that will hold a couple UserControls that we’ll use in the main application.  Pretty standard stuff.

Create 2 UserControls in the library, the first one will use the other.  UserControl1 can just have some container (Grid) then use UserControl2 (which just has an ellipse).  In the main application, add a reference to the ClassLibrary and use UserControl1 in the MainPage.  Your solution should look something like this:

Solution

  <!-- MainPage.xaml -->
  ...
  xmlns:controls="using:ClassLibrary1.Controls"
  ...

<Grid x:Name="LayoutRoot"
    Background="#FF0C0C0C">
  
  <controls:UserControl1 />
  
</Grid>
  <!-- UserControl1.xaml -->
  ...
  xmlns:controls="using:ClassLibrary1.Controls"
  ...

  <Grid x:Name="LayoutRoot"
      Background="#FF0C0C0C">
    
    <controls:UserControl2 />

  </Grid>
  <!-- UserControl2.xaml -->

  <Ellipse Height="40" Width="40" Fill="Red" />

Now here’s the key step.  Add a new class to the ClassLibrary, say Class1, and have that class IMPLEMENT INotifyPropertyChanged (be sure to choose the right using statement – the one from UI.Xaml.Data).

    public class Class1 : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

That’s it.  Run it.

You will get a runtime exception:

Exception

Crazy, huh?  The Microsoft guys have confirmed this to be a known bug.  I just can’t believe what that bug would be?  How is a simple UNREFERENCED class that implements INPC getting in the way of a couple UserControls?

Ahh … the joys of coding against pre-release software…

Windows 8 WinRT Development 101

Let there be no mistake made that it’s pretty exciting that Microsoft is starting to release early bits for some of its products for us to test out. Windows 7, Visual Studio 2008 (Orcas), VS2010, VS11, Win8, etc. are just a few that come to my mind. These early releases are full of bugs and are definitely not production quality, neither should they be. So I’m just going to go ahead and preface everything I’m going to write with, “The Win8 WinRT framework is pre-beta and therefore should not be expected to work exactly as prescribed.” With that said there are a few key features that don’t work as expected and I’ll be touching on some of those.

Motivation
I’m currently on a project with two other developers here at InterKnowlogy, Dan Hanan and Carmine Sampogna. We are at the tail end of porting what we call our Kiosk Framework to Windows 8 on the WinRT framework. The project has been a ton of fun and we’ve learned a lot. The project has not been as straight forward as we would have hoped. WinRT XAML is similar in capabilities to Silverlight 3 and 4. Sometimes you still feel like you’re in SL2, but again it is pre-beta software.
Environment
Carmine and I are running Win8 from bootable VHDs that we made following the steps in a post by another coworker Travis Schilling. Dan received one of the coveted Win8 Tablets from BUILD. And we’ve installed the full developer preview of VS11.

WinRT Gotcha’s
Only one merged resource dictionary supported: We like to organize our XAML Resources into Resource Dictionaries to help with readability. It also allows multiple controls to share a single resource and multiple developers to work on different resources at the same time without the need for merging XAML files. So naturally we went down this path only to find that this is not supported yet in WinRT. We got the following error:

We found some help from someone who had already encountered the problem: http://metrotrenches.wordpress.com/2011/10/07/tailored/.

DependencyProperties are not typed: DependencyProperties are very important when designing UserControls that you intend to be used in different contexts with different DataContexts. In the current version of WinRT DPs are not typed, which is a big bummer. This work around was found at: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/4fed80a8-1343-41ca-8c27-b20a00689f65.

ElementName bindings only sorta-kinda work: ElementName bindings help simplify and centralize values. One element contains the values and a bunch of others can grab those values. They are very important when it comes to attempting to implement a MutltiBinding workaround. However, we have found that in many cases ElementName bindings don’t work while in other cases it does. Not sure why.

Can’t retrieve non-template resources such as double, GridLength, Thickness, etc.: I discovered this because ElementName bindings were failing in a very specific case.


var myGridLegnth = App.Current.Resources["MyGridLength"];  //fails
var myDataTemplate = App.Current.Resources["MyDataTemplate"] as DataTemplate; //works

Works just fine if you are accessing a DataTemplate, ControlTemplate, or Style. However it seems to fail for structs, value types, and complex types.

DataTemplates cannot contain ContentControls that use ContentTemplateSelectors in some cases: I was trying to refactor a DataTemplate into App.xaml (because we can’t have multiple ResourceDictionarys) and I would continually get an Engine Execution Exception.

No Implicit DataTemplates: However there are implicit Styles.

Other Thoughts
One of the most annoying parts about development is that every run of our application is cut short by a FatalExecutionException which claims may be a bug in the CLR, or an ExecutionEngineException with no details. We can’t seem to get around these. Also, any exceptions thrown by bad XAML at runtime have zero details about what is wrong. Sometimes we get exceptions that have nothing to do with XAML or our UserControl but the exception is still thrown by a UserControl. Very Strange.
My coworker Dan has a post with more gotcha’s and his take on Win8. Overall, Win8 is cool, but the preview is severely lacking. We’re hoping it doesn’t take another 6+ months to get new bits!

Windows 8 Development–First Impressions

Along with 5000 other developers, I attended //BUILD/ in September and came home with the Samsung pre-release hardware loaded with Visual Studio 11 and the Win8 bits.  Since then, I’ve been writing a few apps, getting my feet wet writing code for Metro / WinRT apps in C#.  Here are some early impressions on the Windows 8 operating system in general, and then some thoughts on what it takes to develop Metro apps.

Don’t Make Me Hop That Fence Again

The grand new look of Windows 8 is the “Metro” style interface that you see right away on the Start Screen.  The traditional start menu is gone, you don’t have a hierarchy of StartScreenstart menu icons that you wade through, and you don’t have a bunch of icons scattered on your desktop.  Instead you have the clean looking, larger sized “tiles”, some of which are “live”, showing you changes to application data in real-time.    You can find lots of info on the Win8 Metro interface here, so I won’t talk about that.  Apps written for Metro, built against the Windows Runtime (WinRT) run over here on this “Metro” side of the fence.

What is so interesting to me though is that there exists an alternate world in Windows 8 – the classic desktop.  This is where legacy apps run, where the familiar desktop can be littered with icons, the taskbar shows you what’s running,etc. Everything from old C and C++ code to .NET 4 apps run over here on this “Desktop” side of the fence.

DesktopSideSo here then is the problem. Throughout the day, I run a few apps to check Facebook and Twitter (Metro), then I startup Visual Studio 11 (desktop), then I start Task Manager (Metro), then maybe a command prompt (desktop).  Each time I’m in one environment and run an app that runs in the other, the OS switches context to the other side of the fence.  This becomes SUPER ANNOYING over the course of a day.  I’m in the desktop, all I want to do is fire up a command prompt.  Click the start menu (which takes me to the Metro start screen), then choose command prompt, which switches me back to where I just came from and fires up the command prompt.  I’ve become accustomed to pinning all my necessary apps to the desktop side taskbar so I don’t have to go to the Metro screen to run time.

Enough of the Rant – What About Development?

The Windows 8 Runtime (WinRT) is a completely re-written layer akin to the old Win32 API that provides lots of new services to the application developer.  When sitting down to write a new app, you have to decide right away, are you writing a .NET 4.5 app, or are you writing a Metro app.  (This dictates which side of the fence you’ll be hanging out in.)  Some of the coolest features of the Win8 runtime are:

Contracts

Contracts are a set of capabilities that you declare your application to have, and the OS will communicate with your app at runtime based on the contracts.  Technically they’re like interfaces, where you SearchResultspromise to implement a set of functionality so the OS can call you when it needs to.  The most popular contracts are those that are supported by the “Charms” – Search, Share, and Settings.  These are super cool.  Implement a couple methods and your app participates as a search target, so the when the user enters some text in the search charm, your app is listed and you furnish the results.

 

 

protected override void OnLaunched( LaunchActivatedEventArgs args )
{
    var pane = Windows.ApplicationModel.Search.SearchPane.GetForCurrentView();
    pane.QuerySubmitted += QuerySubmittedHandler;

    pane.SuggestionsRequested += SuggestionsRequestedHandler;
    pane.ResultSuggestionChosen += ResultSuggestionChosenHandler;

    pane.PlaceholderText = "Search for something";

	// ...
}

private void QuerySubmittedHandler( SearchPane sender, SearchPaneQuerySubmittedEventArgs args )
{
    var searchResultsPage = new SearchTest.SearchResultsPage1();
    searchResultsPage.Activate( args.QueryText );
}

private void SuggestionsRequestedHandler( SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args )
{
    var searchTerm = args.QueryText;

    var sugg = args.Request.SearchSuggestionCollection;
    for ( int i = 0; i < 5; i++ )
    {
        // just faking some results
        // here you would query your DB or service
        sugg.AppendResultSuggestion( 
            searchTerm + i, 
            "optional description " + i, 
            i.ToString(), 
            Windows.Storage.Streams.StreamReference
              .CreateFromUri( new Uri( "someurl.jpg" ) ),
            "alternate text " + i );
    }

    //defer.Complete();
}

protected override void OnSearchActivated( SearchActivatedEventArgs args )
{
    var searchResultsPage = new SearchTest.SearchResultsPage1();
    searchResultsPage.Activate( args.QueryText );
}

ShareSharing is just about as easy. Declare the contract in your manifest and your app is a share target.  When the user chooses to share to your app, the OS sends you the data the user is sharing and you party on it.

protected override void OnSharingTargetActivated( ShareTargetActivatedEventArgs args )
{
	var shareTargetPage = new ShareTestTarget.SharingPage1();
	shareTargetPage.Activate( args );
}

Settings leave a little bit to be desired in my opinion. You declare the contract, and add a “command” to tell the OS to put in the settings charm panel.  But when the user chooses that command (button), your app has to show its own settings content (usually in a slide out panel from the right).  This is a 4 step process to make any settings changes in your app (swipe from right, touch the button, change settings, dismiss the panel). I really hope in future versions they figure out a way to embed our application settings content right there in the settings panel, not in our own app.

    Windows.UI.ViewManagement.ApplicationLayout.GetForCurrentView().LayoutChanged += LayoutChangedHandler;
    DisplayProperties.OrientationChanged += OrientationChangedHandler;
    Application.Current.Exiting += ExitingHandler;

    SettingsPane pane = SettingsPane.GetForCurrentView();
    SettingsCommand cmd = new SettingsCommand("1", "Pit Boss Settings", (a) =>
        {
            ShowSettingsPanel();
        });
    pane.ApplicationCommands.Add(cmd);

Async Everywhere

The WinRT team has built the APIs with asynchrony in mind from day one. At //BUILD/, we heard over and over that your UI should NEVER freeze because it’s busy doing something in the background.  To that end, any API that could potentially take longer than 50 milliseconds is implemented as an asynchronous method.  Using the async and await keywords (we’ve seen these in a CTP for .NET 4) that are built into the WinRT-based languages, we can write our code in a flowing, linear fashion that makes sense semantically.  No longer do we have to use BackgroundWorkers and worry about marshalling results back to the calling thread.

    HttpClient http = new HttpClient();
    var task = await http.GetAsync( url );

    string responseText = task.Content.ReadAsString();

“Free” Animations

XAML support is implemented in WinRT as native code, and is available to use from C#, VB, and C++.  One of the coolest features they added to what we’re already used to in WPF & Silverlight is the “built-in” animation library.  Simply add any number of transitions on a container element, and any of the associated operations in ANY OF ITS CHILDREN will use that transition.  The list of built-in transitions include: Entrance (content appearing for the first time), Content (change content from old to new), Reposition (fluidly move elements when they get repositioned), Add/Delete (fade out/in and move existing items), and Reorder.

  <Grid>
    <Grid.ChildTransitions>
      <TransitionCollection>
        <EntranceThemeTransition
            HorizontalOffset="500" />
      </TransitionCollection>
    </Grid.ChildTransitions>
  </Grid>

Well, I’ve jumped all around in this post, and it’s long enough already.  Look for future posts with more specifics about features and code that we’re working into our apps.

Some Development Gotchas (aka Bugs)

Here’s a quick list of some issues we’ve run into these first few weeks.

  • You can only set DataContext in code-behind – future releases will allow setting in XAML
  • There are a handful of bugs in FlipView.SelectedItem.  If you’re binding to the SelectedItem property, you have to manually set the SelectedItem to null and then back to the correct property (get it from your ViewModel) in code-behind.  This will obviously be fixed in a future release.
  • You must use ObservableVector<object> based properties in your VMs if you are binding to ItemsControls.ItemsSource and want the UI to update when there are changes to the collection.  ObservableVector<T> does not exist in the class library – you can find source code for it in many of the SDK samples.
  • Use the correct INotifyPropertyChanged implementation (from Windows.UI.Xaml.Data, not System.ComponentModel)
  • There is no VS item template for custom controls in C#, so VS won’t make you the Themes\Generic.xaml structure.  We’re still tracking this one down. We’ve used a Style resource to describe the template for a Button-derived custom control and it works, but you don’t get access to the Template property in OnApplyTemplate, so we’ve resorted to using VisualStateManager instead of referring to template parts and changing UI that way.
  • I’m sure there are more to come … in fact, check out my co-worker Danny’s post (should be up in the next couple days) with more details on what we’ve been encountering while writing our first few Win8 apps.

Check out the Win8 Metro developer forums for ongoing discussions of many other issues.