Using WinRT from C# //build Demo

Yesterday at//build, Jesse Kaplan and I delivered the Using Windows Runtime from C# and Visual Basic talk. In the talk, I demonstrated how natural and familiar it is to use WinRT from C# by building a simple Metro style app. This app  takes a picture with a webcam and implements the share charm contract in less than 15 lines of C# code.

Instead of making you try and read code off the recorded video stream that should be published soon, I’ve written this walkthru to explain exactly what I did in that demo. In addition, I’ve started from scratch (i.e. File->New Project) so that you can follow along at home if you wish.

First, you need to install the Windows Developer Preview. I recommend the x64 version with tools. Scott Hanselman has a great write up on using boot to VHD to run the preview. (though I do disagree w/ his assessment of dual boot. I’ve been dual booting Win7 and Win8 on my laptop for months and it’s never ended in tears or blood). Also, you’re going to need a webcam in order to run the app yourself.

Once the Windows Developer Preview is up and running, run the Socialite app and login with your Facebook credentials. We’re going to use Socialite to share the picture we take with the webcam. Giving it your credentials up front makes the demo run smoother!

Next, fire up VS11 (aka Microsoft Visual Studio 11 Express for Windows Developer Preview). Create a new project and select the Visual C# -> Windows Metro Style -> Application template.

Once the new project has been created, you should be looking at the MainPage.xaml file. Update the Grid element to contain a button and an image.

<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
    <Button x:Name="ClickMe" Click="ClickMe_Click">Click Me</Button>
    <Image x:Name="Photo" Width="800" Height="600"
           HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

Next, hover over the Click=”ClickMe_Click” attribute of the button, right click and select “Navigate to Event Handler”. VS11 will take you to MainPage.xaml.cs and automatically generate a skeleton event handler for you.

In my //build session, I demonstrated that VS11 can automatically resolve WinRT namespaces the same way that it resolves managed namespaces. But for the purposes of this blog post, it’s easier if you just add the additional using statements we’re going to need at the top of MainPage.xaml.cs now.

using Windows.Media.Capture;
using Windows.Storage;
using Windows.UI.Xaml.Media.Imaging;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Streams;

Now, we add the code for ClickMe_Click:

private async void ClickMe_Click(object sender, RoutedEventArgs e)
{
    var ui = new CameraCaptureUI();
    ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);

    var file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);

    if (file != null)
    {
        var stream = await file.OpenAsync(FileAccessMode.Read);

        var bitmap = new BitmapImage();
        bitmap.SetSource(stream);
        Photo.Source = bitmap;
    }
}

A few things to note about this code:

  • Even though it’s using native WinRT libraries, the C# feels natural and familiar – as if you were calling into traditional managed libraries. We’re newing up classes, we’re passing in constructor parameters, we’re using primitive numbers and enums, we’re assigning properties, etc. That is very much by design.
  • We’re using a couple of async WinRT methods (CaptureFileAsync and OpenAsync). C# 5.0′s new await keyword to make it extremely easy to write linear looking code that doesn’t block on async operations.
  • No P/Invoke or COM Interop attributes anywhere to be seen!

Finally, before we can run this code we need to declare our intent to use the webcam. Double click on the Package.appxmanifest file, click on the “Capabilites” tab, and then check the Webcam checkbox.

With the capability declared, now we can run the app. Hit F5 and VS11 will compile and deploy the Metro style app you just built. Click the button, acknowledge that you want to let the program use the webcam, take a pic, crop it, and there it is in your UI!

For the second part of the demo, I added share contract support. Here’s how to do that.

First, we need to pull the stream variable into class instance scope so that we can access it in the share contract event handler. We do that by adding a private IRandomAccessStream variable named stream and removing the var declarations from the line where we call OpenAsync. The updated click event handler looks like this:

//here's the instance scope stream variable
IRandomAccessStream stream;

private async void ClickMe_Click(object sender, RoutedEventArgs e)
{
    var ui = new CameraCaptureUI();
    ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);

    var file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);

    if (file != null)
    {
        //the only change from the code above was to remove
        //the var declaration from the following line
        stream = await file.OpenAsync(FileAccessMode.Read);

        var bitmap = new BitmapImage();
        bitmap.SetSource(stream);
        Photo.Source = bitmap;
    }
}

Next, we need to wire up the share event handler in the XAML page’s constructor. That’s a single line of code and VS11 intellisense writes most of  it for you

public MainPage()
{
    InitializeComponent();
    DataTransferManager.GetForCurrentView().DataRequested +=
        new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(MainPage_DataRequested);
}

If you’ve ever wired up an event handler in C# before with VS, you’ll be familiar with the “Press TAB to insert” the correct event handler type followed by “TAB to generate handler”. Even though hthis is a WinRT event, VS11 helps you wire it up just the same as it does for managed events.

Now we implement the share contract event handler. That’s just a simple if statement – calling args.Request.Data.SetBitmap if the user has taken a picture and calling args.Request.FailWithDisplayText with an error message if they have not.

private void MainPage_DataRequested(DataTransferManager sender,
    DataRequestedEventArgs args)
{
    if (stream == null)
        args.Request.FailWithDisplayText("No picture taken!");
    else
        args.Request.Data.SetBitmap(stream);
}

This part of the demo shows off static methods and event handlers. Again, note how natural and familiar it feels to use WinRT from C#.

And we’re done, so hit F5 to build, deploy and run the app again.

I didn’t remember to do this in the //build talk, but first try selecting the share contract before taking a picture. Windows will display the “No picture taken” text in share contract window since the user taken a picture to share yet. That’s pretty boring so dismiss the share contract and take a picture like you did before. Then select the share contract, select Socalite, write a pithy message and press “Share in Facebook”.

That’s the entire demo! Taking a picture with the webcam, uploading to facebook, calling native WinRT APIs from C# in a natural and familiar way and all in just under 15 lines of code!

With our talk and demos, Jesse and I wanted to communicate just how important C# and VB are in the overall developer story for Windows 8. This demo shows off the hard work our two teams have done in order to make sure the managed developer’s experience with Windows 8 was the best that it could be. As I said in the talk – if you’re a managed developer, you already know how to build these Metro style apps.

I know I said it before, but I really can’t wait to see what you guys build with Windows 8!

Comments:

Well we won't be building enterprise apps in silverlight that's for sure! :-(
Hi! Great talk, even it I only saw the recording! Only, I still have some problems understanding the plumbing behind the WinRT/CLR stuff: Given, for example a WinRT call that returns a vector or a Map, what do I really get? Like, will the CLR GC be able to move it around, like native .NET objects? Will a foreach (WinRTObject O in X.GetWinRTCollection()) { dowomethingWith(O;) } involve COM interop and RTW stuff? I've asked this in but so far didn't get enlightened very much. Very nice talk! Volker
Glad you liked the talk Volker! As I said in the talk, WinRT is built on a foundation of COM. So, yes, whenever you use WinRT from C#, you're using COM interop and RCWs (I'm assuming you meant "RCW" aka Runtime Callable Wrapper when you wrote "RTW stuff".) As you might imagine, I took the weekend off, but I'll be surfing the forums regularly answering questions in the future.
Thanks for the helpful write up. One thing...the demo doesn't unhook the DataRequested event of the DataTransferManager. Unless there are weak events being used in WinRT, this sample code probably causes a memory leak because the MainPage is always referenced by an instance of DataTransferManager (whose lifetime I assume is greater than that of the page). Or is there some new greatness in WinRT's eventing model that I'm not aware of? Thanks, Josh
A quick couple of questions: 1) If an app is written in pure XAML - say a grid with a few boxes - with no code of any kind (c#/javascript/c++) - are any dotnet libs/runtime's loaded? Does XAML in Win8/Metro have any dotnet dependencies? Is the code that renders the declarative XAML 2) Can javascript project be written to work with XAML instead of HTML.
1) I'm not sure how compelling a pure XAML app would be. But Windows XAML does not depend on .NET. If you build a Metro style app with XAML and C++, you don't load the CLR. 2) No, JS only works with HTML.