Another new feature of Windows Phone 7.1 that every developer should know about is secondary tiles. Windows Phone 7.0 allowed users to pin an app to the Start screen, creating a tile for that app. But it limited apps to one tile each, and it provided no mechanism for passing information to an app launched from a tile.

Enter Windows Phone 7.1, which allows apps to create additional tiles – “secondary tiles” – on the Start screen, and to embed a link containing unique information in each one. Secondary tiles can’t be created directly by a user; they can only be created from your code. They’re useful because they support deep linking into your app, each one representing your app in a different state.

To demonstrate, I wrote an app named SecondaryTileDemo, which is pictured below. Take it for a spin by typing a zip code into the text box at the top of the screen and pressing the button to its right. The app responds by displaying the current temperature at that location, which it obtains by firing off a call to a REST service at www.wunderground.com.

SecondaryTileDemo1

Once you’ve retrieved the current temperature for the location of your choice, press the + button in the application bar to create a secondary tile on the Start screen representing that location. Repeat this process a few times to create several secondary tiles, each representing a different zip code:

SecondaryTileDemo2

Now tap one of the secondary tiles you created. The app gets launched, and without additional user input, it shows the current temperature at the corresponding location. This is the power of secondary tiles and deep linking: it affords the user the ability to create multiple shortcuts to your app, and to encapsulate information in each shortcut to launch your app in a different state.

You can download SecondaryTileDemo and examine the source code to see how it works. Of course, you’ll need to have the Windows Phone 7.1 Beta 2 dev tools installed on your box to run it. The action begins with the event handler for the application-bar button, which uses Mango’s new ShellTile.Create method to create a secondary tile that points to MainPage.xaml with a query string containing the current zip code:

 

ShellTile tile = ShellTile.ActiveTiles.FirstOrDefault(x =>

    x.NavigationUri.ToString().Contains("zip=" + _zip));

 

if (tile == null)

{

    StandardTileData data = new StandardTileData

    {

        BackgroundImage = new Uri("Images/sky.jpg", UriKind.Relative),

        Title = Location.Text

    };

 

    ShellTile.Create(new Uri("/MainPage.xaml?" + _key + "=" + _zip,

        UriKind.Relative), data);

}

 

The first statement uses a LINQ query to make sure the Start screen doesn’t already contain a tile with the corresponding zip code. If no such tile exists, the app creates a StandardTileData object specifying the tile’s title (the text that appears at the bottom of the tile) and background image, and then passes it to ShellTile.Create. Although not shown here, StandardTileData also contains properties that you can use to put content on the back of the tile – another innovation that Mango brings to the platform.

When the user taps a secondary tile, the app is launched and the URI passed to ShellTile.Create is activated. In this example, that activates MainPage, whose OnNavigatedTo override reads the zip code from the query string and launches a new Web request to get the current temperature:

 

// If this page was activated from a tile, launch a request for

// the current weather at the location indicated in the query string

if (NavigationContext.QueryString.ContainsKey(_key))

{

    string zip = NavigationContext.QueryString[_key];

 

    if (zip.Length == 5)

    {

        HttpWebRequest request =

            (HttpWebRequest)HttpWebRequest.Create(new Uri("..." + zip));

        request.BeginGetResponse(new AsyncCallback(OnGetResponseCompleted),

            request);

        ZipCode.Text = zip;

        WeatherButton.IsEnabled = false;

    }

 

    // Remove the zip code from the query string (important!)

    NavigationContext.QueryString.Remove(_key);

}

 

Note the final statement, which removes the zip code from the query string. That’s important, because if the user navigates away from the app but returns to it with the Back button, the query string is passed in again. If you honor the query string but the user had fetched the temperature at another location before navigating away, the app will be restored to its original state rather than its previous state. As it is, we only grab weather data when the app is first launched from a tile, and rely on tombstoning logic to persist the state thereafter. (There are other ways to handle this, but this was a simple and effective means for doing it in this example.)

Speaking of tombstoning…as you may have heard, Mango adds an interesting twist to the tombstoning story. Apps that are switched away from frequently aren’t deactivated as they were in 7.0. Instead, they’re put into a dormant state, in which the process is suspended but the process image – along with its current state – remains in memory.  The OnNavigatedTo method in this example has been subtly altered to reflect this new reality. Can you spot the difference? If not, don’t fret. I intend to make that the subject of my next article.

One of the most exciting new features coming in Windows Phone 7.1, code-named “Mango,” is an HTML5 Web browser based on IE9. One by-product of this addition is that you can use Mango phones to browse HTML5 Web sites. But the greater implication is that developers can now use HTML5 to build cross-platform mobile applications that run on Windows phones as well as iPhones and Android phones.

HTML5 isn’t a perfect solution for building cross-platform mobile apps – you can’t, for example, leverage native features such as Mango’s Pivot and Panorama controls from HTML5, nor would you want to since those controls don’t exist on other platforms – but for apps that don’t need platform-specific features anyway, HTML5 offers a handy solution to the problem of having to write the same app multiple times to get it running on different devices.

To demonstrate the basic steps involved in writing Mango apps in HTML5 and packaging them and deploying them to a phone, I wrote the app pictured below. It’s a classic sliding-puzzle game, in which you scramble the picture and then try to get the pieces back in the right place. To move, simply touch a piece that’s adjacent to the empty (gray) square. Each puzzle piece is an HTML5 canvas, and I used jQuery animations to slide puzzle pieces up, down, and sideways. You can download the source code and play with it on your phone if your phone has been flashed for Mango. If not, you’ll have to use the emulator, but be aware that the app only works in the emulator if the PC it’s running on has sufficient GPU support.

HTML5Demo Screen

Writing an HTML5 app for a Windows phone – or any phone, for that matter – begins with the HTML assets. My app contains three such assets:

  • Puzzle.html, the page that comprises the app’s UI
  • jquery.js, which contains version 1.5 of the popular jQuery library
  • scene.jpg, which contains the 480 x 800 image from which puzzle pieces are generated

Puzzle.html is reproduced below. Nothing magical here – just 14 HTML5 canvases, or one for each puzzle piece; some JavaScript code that cuts up the 480 x 800 image and paints the puzzle pieces; and more JavaScript code to move a puzzle piece in response to click events. I tested this page in IE9 and other HTML5 browsers before incorporating it into my phone app.

 

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=480, height=800, user-scalable=no" />

<style type="text/css">

body {

    margin: 0;

    height: 100%;

    background-color: #808080;

}

#main {

    position: absolute;

    width: 480px;

    height: 800px;

}

</style>

 

<script type="text/javascript" src="jquery.js"></script>

 

<script type="text/javascript">

    var _row = 4; // Row containing empty square

    var _col = 2; // Column containing empty square

 

    $(document).ready(function () {

        // Load the puzzle image

        var image = new Image();

        image.src = "scene.jpg";

        image.onload = function () {

            // Draw sections of the image into the puzzle pieces

            for (var row = 0; row < 5; row++) {

                for (var col = 0; col < 3; col++) {

                    if (!(row == 4 && col == 2)) {

                        var dc = document.getElementById("c" +

                            row + col).getContext("2d");

                        dc.drawImage(image, col * 160, row * 160, 160, 160,

                            0, 0, 160, 160);

                    }

                }

            }

 

            // Wire event handlers to all the puzzle pieces

            $("canvas").click(onClick);

        }

    });

 

    function onClick(e) {

        var piece = $(this);

 

        // Get the row and column

        var row = piece.position().top / 160;

        var col = piece.position().left / 160;

 

        if (row == _row && col == _col + 1) {

            // Move left

            piece.animate({ left: "-=160px" }, 100);

            _col++;

        }

        else if (row == _row && col == _col - 1) {

            // Move right

            piece.animate({ left: "+=160px" }, 100);

            _col--;

        }

        else if (col == _col && row == _row + 1) {

            // Move up

            piece.animate({ top: "-=160px" }, 100);

            _row++;

        }

        else if (col == _col && row == _row - 1) {

            // Move down

            piece.animate({ top: "+=160px" }, 100);

            _row--;

        }

    }

</script>

 

</head>

<body>

 

<div id="main">

    <canvas id="c00" width="160px" height="160px" style="position: absolute;

        left: 0px; top: 0px; border: 1px solid gray"></canvas>

    <canvas id="c01" width="160px" height="160px" style="position: absolute;

        left: 160px; top: 0px; border: 1px solid gray"></canvas>

    <canvas id="c02" width="160px" height="160px" style="position: absolute;

        left: 320px; top: 0px; border: 1px solid gray"></canvas>

    <canvas id="c10" width="160px" height="160px" style="position: absolute;

        left: 0px; top: 160px; border: 1px solid gray"></canvas>

    <canvas id="c11" width="160px" height="160px" style="position: absolute;

        left: 160px; top: 160px; border: 1px solid gray"></canvas>

    <canvas id="c12" width="160px" height="160px" style="position: absolute;

        left: 320px; top: 160px; border: 1px solid gray"></canvas>

    <canvas id="c20" width="160px" height="160px" style="position: absolute;

        left: 0px; top: 320px; border: 1px solid gray"></canvas>

    <canvas id="c21" width="160px" height="160px" style="position: absolute;

        left: 160px; top: 320px; border: 1px solid gray"></canvas>

    <canvas id="c22" width="160px" height="160px" style="position: absolute;

        left: 320px; top: 320px; border: 1px solid gray"></canvas>

    <canvas id="c30" width="160px" height="160px" style="position: absolute;

        left: 0px; top: 480px; border: 1px solid gray"></canvas>

    <canvas id="c31" width="160px" height="160px" style="position: absolute;

        left: 160px; top: 480px; border: 1px solid gray"></canvas>

    <canvas id="c32" width="160px" height="160px" style="position: absolute;

        left: 320px; top: 480px; border: 1px solid gray"></canvas>

    <canvas id="c40" width="160px" height="160px" style="position: absolute;

        left: 0px; top: 640px; border: 1px solid gray"></canvas>

    <canvas id="c41" width="160px" height="160px" style="position: absolute;

        left: 160px; top: 640px; border: 1px solid gray"></canvas>

</div>

 

</body>

</html>

 

Once the HTML assets are finalized, the challenge is to package them into a native phone app – one that can be deployed through the Windows Phone Marketplace like any other app. Here were the steps involved in this example:

  1. Create copies of Puzzle.html, jquery.js, and scene.jpg in isolated storage
  2. Create a WebBrowser control and point it to Puzzle.html

Here’s the corresponding code in MainPage.xaml.cs. “Browser” is the name assigned to the WebBrowser control I declared in MainPage.xaml. (Be sure to set the control’s IsScriptEnabled property to true; otherwise, your JavaScript won’t work very well, to put it mildly.)

 

// Constructor

public MainPage()

{

    InitializeComponent();

 

    // If the HTML assets aren't in isolated storage, put them there

    using (IsolatedStorageFile store =

        IsolatedStorageFile.GetUserStoreForApplication())

    {

        if (!store.FileExists("Puzzle.html"))

            CreateFile(store, "Puzzle.html", Application.GetResourceStream

                (new Uri("Assets/Puzzle.html", UriKind.Relative)).Stream);

 

        if (!store.FileExists("jquery.js"))

            CreateFile(store, "jquery.js", Application.GetResourceStream

                (new Uri("Assets/jquery.js", UriKind.Relative)).Stream);

 

        if (!store.FileExists("scene.jpg"))

            CreateFile(store, "scene.jpg", Application.GetResourceStream

                (new Uri("Assets/scene.jpg", UriKind.Relative)).Stream);

    }

 

    // Once the WebBrowser control has loaded, point it to Puzzle.html

    Browser.Loaded += (s, e) => Browser.Source =

        new Uri("Puzzle.html", UriKind.Relative);

}

 

private void CreateFile(IsolatedStorageFile store, string file, Stream content)

{

    using (IsolatedStorageFileStream stream =

        new IsolatedStorageFileStream(file, FileMode.Create, store))

    {

        using (BinaryReader reader = new BinaryReader(content))

        {

            byte[] data = reader.ReadBytes((int)content.Length);

 

            using (BinaryWriter writer = new BinaryWriter(stream))

            {

                writer.Write(data);

            }

        }

    }

}

 

I added Puzzle.html, jquery.js, and scene.jpg to the phone project and set each file’s build action to Content. (I placed these files in a folder named Assets, which explains the “Assets” in the path names passed to Application.GetResourceStream. For reference, see the solution structure below.) Each time the app starts up, it checks to see if these files are in isolated storage. If they’re not, it puts them there. I chose to put all three files in the root directory of the application’s isolated storage, but you could just as easily segregate them into subdirectories and modify the URIs referencing them in Puzzle.html accordingly.

image

The net result is an app that looks like a native Mango app, but is in fact an HTML5 app that is easily ported to other platforms. Is this the future of mobile development? You be the judge. What’s important is that it’s finally an option on Windows phones, and that the presence of HTML5 support will only bolster the variety of apps available for these devices.

Silverlight 5 boasts a wealth of sexy new features, including a full-blown, hardware-accelerated 3D graphics API, support for custom markup extensions, multiple-window support in trusted out-of-browser apps, and the ability to run trusted applications in the browser (with sufficient permissions, of course). Post-beta, even more features will be added, such as support for invoking native operating system services using P/Invoke. But some of the most significant new features of the platform threaten to fly under the radar because they don’t lend themselves to glitzy demos. Among those features is a subtle but welcome change to Silverlight 5’s internal threading architecture.

That change is the introduction of a composition thread – a trick borrowed from Silverlight for Windows Phone. In Silverlight 4, the UI thread is responsible for virtually everything that matters: processing user input, rendering output, running animations, and more. As a result, long-running loops on the UI thread – something that developers must avoid at all costs – have debilitating effects. For example, if you’re running an animation and enter a 5-second for loop on the UI thread, the animation pauses for 5 seconds. That’s because Silverlight can’t do two things at once on a single thread, and while you’re executing code on the UI thread, Silverlight can’t use it to render changes to the visual tree, run animations, and so on.

Silverlight 5 changes this by offloading some of the work traditionally done by the UI thread to another thread called the composition thread. When present, the composition thread takes responsibility for managing operations that involve the GPU. For example, if an animation is running and IF the surface being animated is GPU-cached, then that animation will run entirely on the composition thread. The practical effect is that animations won’t stop if the UI thread is tied up performing other tasks.

It is important to note that the composition thread ONLY applies to GPU operations. If the object being animated isn’t GPU-cached – for instance, if you haven’t set that object’s CacheMode property to “BitmapCache” – then the composition thread doesn’t get involved. In fact, if you haven’t enabled GPU acceleration to begin with, there IS no composition thread. So to leverage the composition thread, you must 1) enable GPU acceleration in the application, and 2) make sure the objects you’re animating are handed off to the GPU. The first rasterization of those objects (and any rerasterizations resulting from changes to the objects’ visual properties) still takes place on the UI thread, but once that’s done, the composition thread takes over and drives any animations involving those objects. Unlike Silverlight for Windows Phone, Silverlight 5 doesn’t support GPU auto-caching, so you must be explicit about telling the run-time which parts of the visual tree to compose on the GPU.

While the addition of a composition thread doesn’t lend itself to eye-catching demos as the 3D graphics API does, there is a simple way to see the composition thread in action. The application pictured below uses three DoubleAnimations to continuously scale and rotate a Canvas containing a partially transparent penguin. Initially, because GPU acceleration isn’t enabled, the animations are driven by the UI thread. To demonstrate, click anywhere in the browser window while the animations are running. Doing so activates a MouseLeftButtonDown handler that calls Thread.Sleep() to put the UI thread to sleep for 2 seconds. When you click, the animations pause.

CompositionThreadDemo

Now go into CompositionThreadDemoTestPage.html and change enableGpuAcceleration from false to true:

 

<param name="enableGpuAcceleration" value="true" />

 

Then run the application and click again. Voila! The penguin doesn’t stop animating. Why? Because the animations are now running on the composition thread. The penguin Canvas is GPU-cached because I already have its CacheMode property set to “BitmapCache.” And now that GPU acceleration is enabled, the composition thread automatically assumes responsibility for running the animations. If you tried the same experiment in Silverlight 4, the animations would pause despite the fact that the penguin is GPU-cached.

Does this mean that in Silverlight 5, it’s OK to execute long-running loops on the UI thread? Absolutely not. Non-GPU rendering is still performed on the UI thread, so if you make changes to the visual tree in a loop, those changes won’t be rendered until you exit the loop. But the composition thread allows animations to run more smoothly when the UI thread is busy doing other things, and it allows the application as a whole to be more responsive to user input by reducing the amount of work that the UI thread has to do. This is a significant step forward in the architecture of the run-time, and it brings Silverlight for the desktop up to par with Silverlight for Windows Phone as far as composition is concerned.

Another of the minor but potentially useful new features coming in Silverlight 5 – and already present in the Silverlight 5 beta – is style data binding. Simple put, style data binding allows you to use data-binding expressions to assign values to style setters. It may not sound that exciting, but among other things, it makes it easier than ever to include dynamic theming support in your Silverlight apps. There’s not a lot of documentation around this feature just yet, but as usual, a good example is better than documentation anyway.

I built the app shown below to demonstrate dynamic theming using style data binding. Here’s how it looks when it first appears on the screen:

StyleDataBinding1

Clicking anywhere in the browser window instantly changes the theme colors:

StyleDataBinding2

To make this work, and to leverage style data binding, I began by writing a simple class named ColorTheme that exposes brushes and colors through properties with names like AccentColor, AccentBrush, and TextBrush. (I also implemented INotifyPropertyChanged in the class since I intended to use it as a data source.) Then, in App.xaml, I declared an instance of ColorTheme, and I defined a few styles that use {Binding} expressions to reference ColorTheme properties:

 

<Application.Resources>

  <!-- Color theme -->

  <local:ColorTheme x:Key="Theme" />

       

  <!-- Styles that data-bind to color theme -->

  <Style x:Key="NormalText" TargetType="TextBlock">

    <Setter Property="FontFamily" Value="Segoe WP" />

    <Setter Property="FontSize" Value="16" />

    <Setter Property="Foreground"

      Value="{Binding TextBrush, Source={StaticResource Theme}}" />

  </Style>

 

  <Style x:Key="AccentText" TargetType="TextBlock">

    <Setter Property="FontFamily" Value="Segoe WP" />

    <Setter Property="FontSize" Value="16" />

    <Setter Property="Foreground"

      Value="{Binding AccentBrush, Source={StaticResource Theme}}" />

  </Style>

 

  <Style x:Key="BackgroundGradient" TargetType="Panel">

    <Setter Property="Background">

      <Setter.Value>

        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

          <GradientStop Offset="0"

            Color="{Binding BackgroundColor, Source={StaticResource Theme}}" />

          <GradientStop Offset="1"

            Color="{Binding AccentColor, Source={StaticResource Theme}}" />

        </LinearGradientBrush>

      </Setter.Value>

    </Setter>

  </Style>

</Application.Resources>

 

In MainPage.xaml, I applied the data-bound styles to XAML elements:

 

<Grid x:Name="LayoutRoot" Style="{StaticResource BackgroundGradient}"

  MouseLeftButtonDown="OnClick">

  <Grid.RowDefinitions>

    <RowDefinition Height="Auto"/>

    <RowDefinition Height="*"/>

  </Grid.RowDefinitions>

 

  <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">

    <TextBlock Text="STYLE DATA BINDING DEMO"

      Style="{StaticResource NormalText}" />

    <TextBlock Text="silverlight 5 rocks!" FontSize="60"

      Style="{StaticResource AccentText}" />

  </StackPanel>

 

  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

    <TextBlock Style="{StaticResource NormalText}" TextWrapping="Wrap"

        Text="..." />

  </Grid>

</Grid>

 

With this infrastructure in place, changing a theme color is as simple as changing the corresponding property in the ColorTheme object. To facilitate this, I built a public method named ToggleColors into the ColorTheme class. The OnClick handler calls that method on the instance of ColorTheme declared in App.xaml:

 

private void OnClick(object sender, MouseButtonEventArgs e)

{

    // Toggle theme colors

    (Application.Current.Resources["Theme"] as ColorTheme).ToggleColors();

}

 

ToggleColors, in turn, updates the colors and brushes. Here, for example, is how it switches from the bluish theme to the orangish theme:

 

BackgroundColor = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);

AccentColor = Color.FromArgb(0xFF, 0xF0, 0x96, 0x09);

BackgroundBrush = new SolidColorBrush(BackgroundColor);

AccentBrush = new SolidColorBrush(AccentColor);

TextBrush = new SolidColorBrush(Colors.Black);

 

You can download the Visual Studio solution and try it for yourself. The style story has improved in every version of Silverlight since version 2. It’s nice to see that version 5 is no exception!

Silverlight 5 boasts a lot of big new features, but sometimes it’s the little things that count. A case in point is the new RichTextBoxOverflow control, which simplifies the process of implementing newspaper-style layouts in Silverlight applications. It may not be as sexy as the new 3D graphics API, but RichTextBoxOverflow will be your best friend if you want to build readers for newspapers, magazines, books, or other richly formatted content, and you want text to flow between columns as the size of the text (or the text container) changes.

To demonstrate, I built a simple example that you can download and try for yourself if you have the Silverlight 5 beta installed on your development machine. When it first comes up, it looks something like this:

OverflowText1

Now grab the slider that’s directly underneath the text and move it to the right. The text in the article will increase in size and automatically flow from column 1 to column 2:

OverflowText2

Next, use the bottom slider to change the text leading – that is, the spacing between characters:

OverflowText3

This, too, is new in Silverlight 5, and changing the character spacing causes text to flow between columns as the volume of the text changes. You can also make the text flow by resizing the browser window. All of this would have been incredibly difficult to do in Silverlight 4, but in Silverlight 5, it’s a piece of cake.

So how does it work? How do you create multi-column text displays and flow text from one column to another? And how do you adjust the leading for added control over how your text is displayed? Here’s the key markup from MainPage.xaml:

 

<RichTextBox x:Name="Column1"

  OverflowContentTarget="{Binding ElementName=Column2}"

  FontFamily="Georgia" FontSize="{Binding Value, ElementName=FontSizeSlider}"

  CharacterSpacing="{Binding Value, ElementName=CharacterSpacingSlider}">

    .

    .

    .

</RichTextBox>

 

<RichTextBoxOverflow x:Name="Column2" />

 

First you declare a RichTextBox control for column 1. Then you declare a RichTextBoxOverflow control for column 2, and you connect the two together by pointing the RichTextBox control’s OverflowContentTarget property to the RichTextBoxOverflow control. Now any text that won’t fit inside the RichTextBox will automatically spill over into the RichTextBoxOverflow control, and if you want to add a third column, you can simply declare another RichTextBoxOverflow control and chain the first RichTextBoxOverflow to the second using the former’s OverflowContentTarget property.

As for character spacing, you control that with the new CharacterSpacing property. In this example, I simply bound the RichTextBox’s CharacterSpacing property to a Slider control, just as I bound FontSize to a Slider. Also note that I didn’t have to set FontFamily, FontSize, and other font-related properties on the RichTextBoxOverflow control, because these property values flow from the RichTextBox just like the text itself.

Hard to imagine how it could be any easier. It’ll be interesting to see how developers use these features to richen up their UIs.

The first beta of Silverlight 5 was announced at MIX this week and is available for downloading. As such, I’ll be blogging about the new features in weeks to come. I’ll also be delivering sessions on Silverlight 5 at several upcoming conferences, including Microsoft TechDays in Belgium, Microsoft DevDays in the Netherlands, Devscovery in Redmond, WA, and Microsoft TechEd in Atlanta. If you plan to attend any of those conferences, I’d love to see you in my sessions!

One of the most exciting features that Silverlight 5 introduces – and one that has been a long time in coming to the platform – is custom markup extensions. My fellow coconspirator and Silverlight MVP Jeremy Likness presented a custom markup extension that uses MEF to satisfy imports on object instances declared in XAML. I’d like to present a custom markup extension of my own – one that retrieves RESX localization resources and simplifies the task of adding localization support to Silverlight applications.

In the past, RESX-based localization was usually performed in Silverlight XAML with the help of the built-in {Binding} markup extension. To demonstrate, the following example declares an instance of the ResourceManager wrapper class named Resources (which is generated by Visual Studio from Resources.resx), assigns the Resources instance to the DataContext property of a TextBlock, and uses a data-binding expression to set the TextBlock’s Text property equal to the Greeting property of the Resources instance:

 

<Grid>

  <Grid.Resources>

    <local:Resources x:Key="Localize" />

  </Grid.Resources>

  <TextBlock Text="{Binding Greeting}" DataContext="{StaticResource Localize}" />

</Grid>

 

It works, but it makes you wonder why you have to resort to data binding to make localization work when localization is such a common task in Silverlight applications.

You can make this work a little more cleanly by writing a custom markup extension. Such an extension might be applied this way:

 

<Grid>

  <TextBlock

    Text="{local:Resx ResxKey=Greeting, ResxType=Resources, Default=Welcome}" />

</Grid>

 

In this example, Resx is the custom markup extension, ResxKey identifies the localization resource to be loaded, ResxType identifies the ResourceManager wrapper class that provides access to that resource, and Default is an optional default value that’s used if the specified localization resource doesn’t exist or can’t be retrieved. Better, is it not? And it’s just one of a million different applications for custom markup extensions.

Implementing a custom markup extension is, in most cases, relatively straightforward. You begin by deriving from Silverlight 5’s new System.Windows.Markup.MarkupExtension class. Then you override ProvideValue in the derived class and return the value generated by the markup extension. My ResxExtension class is implemented this way:

 

public class ResxExtension : MarkupExtension

{

    public string ResxType { get; set; }

    public string ResxKey { get; set; }

    public object Default { get; set; }

 

    public override object ProvideValue(IServiceProvider serviceProvider)

    {

        if (!String.IsNullOrEmpty(ResxType) && !String.IsNullOrEmpty(ResxKey))

        {

            try

            {

                // Create a strongly typed resource manager instance

                object resman = Activator.CreateInstance(Type.GetType(ResxType));

 

                // Get the value of the specified property

                PropertyInfo pi = resman.GetType().GetProperty(ResxKey);

                return pi.GetValue(resman, null);

            }

            catch (Exception)

            {

                // Purposely do nothing here to allow the call to fall through

            }

        }

 

        // If we make it to here, return the default value (if specified) or,

        // as a last resort, the key name

        if (Default != null)

            return Default;

        else

            return ResxKey;

    }

}

 

The three public properties – ResxType, ResxKey, and Default – define the named parameters that the markup extension accepts. The XAML parser automatically initializes these properties with the values provided in the markup. My ProvideValue override uses reflection to create an instance of the ResourceManager wrapper class identified by ResxType, and then uses reflection again to retrieve the value of the property whose name is stored in the markup extension’s ResxKey property. If anything goes wrong, ProvideValue returns the default value specified with the Default parameter, or the value of ResxKey if there is no Default parameter.

If you’d like to see ResxExtension in action, you can download a zip file containing the Visual Studio solution. When you run the app for the first time, you’ll see this:

ResxExtension1

But if you open App.xaml.cs and uncomment line of code that sets the culture to French, you’ll see this instead:

ResxExtension2

The welcome text, the URI of the flag image, and the width of the flag image come from RESX files named Resources.resx, Resources.fr.resx, Resources.es.resx, and Resources.de.resx. Open these RESX files in Visual Studio and you’ll see exactly how the individual resources are defined. As for applying the localization resources, that happens in MainPage.xaml:

 

<TextBlock Text="{local:Resx ResxKey=Greeting,

  ResxType=CustomMarkupExtensionDemo.Localization.Resources, Default='Nice Try!'}"

  Foreground="LightYellow" FontSize="72" FontWeight="Bold"

  HorizontalAlignment="Center" VerticalAlignment="Center">

  <TextBlock.Effect>

    <DropShadowEffect BlurRadius="12" ShadowDepth="12" Opacity="0.5" />

  </TextBlock.Effect>

</TextBlock>

<Image Source="{local:Resx ResxKey=FlagUri,

  ResxType=CustomMarkupExtensionDemo.Localization.Resources}"

  Width="{local:Resx ResxKey=FlagWidth,

  ResxType=CustomMarkupExtensionDemo.Localization.Resources}" />

 

Examine the source and see what kinds of cool custom markup extensions you can come up with. And don’t forget that you’ll need to download and install the Silverlight 5 Beta to run the example.

HTML5’s Canvas and CanvasRenderingContext2d bring something to HTML5 that has long been missing from HTML: the ability to draw pixels into a browser window. I wrote about the canvas API in a previous post entitled Making HTML5 Come Alive with the Canvas API. This time, I’d like to build on that post by exploring a subject for which HTML5 provides no native support: canvas animations.

Silverlight has a robust animation engine built in that makes it easy to make objects move around the screen. HTML5 does not, but you can use timer functions to move objects around by repositioning them at regular intervals. Because HTML5’s canvas API is an immediate-mode drawing API (as opposed to Silverlight’s retained-mode API), moving an object from one position to another requires you to erase it from its current position before drawing it in its new position. Erase, draw, repeat – that’s the basic technique for animating movement within a canvas in HTML5. But as you’ll see, it’s possible to animate CSS properties of the canvas itself to lend the whole affair a retained-mode feel.

For a demonstration, point an HTML5 browser such as Internet Explorer 9, Firefox 4, Chrome 10, Opera 11, or Safari 5 to http://www.wintellect.com/html5/MovingAnimation1.html. You’ll see a page containing a red ball that measures 100 pixels in diameter bouncing around in a 400x400 canvas:

Animation1

Here’s the code that animates the red ball. Every 10 milliseconds or so, the move function erases the ball by calling CanvasRenderingContext2d’s clearRect method. Then it computes the ball’s new position and draws a red circle there. Like frames in a video, it creates the illusion of motion:

 

// Set a timer to fire every 10 milliseconds

setInterval("move()", 10);

 

function move() {

    // Erase the circle from its old position

    _dc.clearRect(_x – 50, _y – 50, 100, 100);

 

    // Compute the circle's new position

    var x = _x + _dx;

 

    if (x < 51 || x > (_cx - 51)) {

        x = _x - _dx;

        _dx = -_dx;

    }

 

    var y = _y + _dy;

 

    if (y < 51 || y > (_cy - 51)) {

        y = _y - _dy;

        _dy = -_dy;

    }

 

    _x = x;

    _y = y;

 

    // Redraw the circle in its new position

    _dc.fillStyle = "red";

    _dc.beginPath();

    _dc.arc(_x, _y, 50, 0, Math.PI * 2, true);

    _dc.fill();

}

 

Nothing hard about that. And one of the nice things about clearRect is that works equally well against complex backgrounds. To see what I mean, check out the page at http://www.wintellect.com/html5/MovingAnimation2.html. Unlike its predecessor, it animates a ball against a background consisting of a wood-grain image. For good measure, it also uses a radial gradient fill to make the ball look a little more realistic:

Animation2

While there’s nothing inherently wrong with animating an object this way, developers used to retained-mode graphics subsystems will come away feeling a little cold. Wouldn’t it be nice if there were a way draw the ball once and then move it around the screen without having to continually erase and redraw it? Funny you should ask. Because with a little help from CSS, you can do just that.

The third example in this series – http://www.wintellect.com/html5/MovingAnimation3.html – does things a little differently. It looks the same on the outside, but on the inside, instead of erasing and redrawing a ball in a 400x400 canvas, it draws the ball once in a 100x100 canvas. Then it uses a timer function to animate the canvas’s CSS left and top properties. Now the browser takes care of doing the erasing and redrawing. Here’s the modified move function:

 

function move() {

    // Get the ball's current position

    var left = _canvas.style.left;

    var top = _canvas.style.top;

 

    var x = parseInt(left.substring(0, left.length - 2));

    var y = parseInt(top.substring(0, top.length - 2));

 

    // Compute the ball's new position

    x += _dx;

 

    if (x < 0 || x > (_cx - 101)) {

        _dx = -_dx;

        x += (2 * _dx);

    }

 

    y += _dy;

 

    if (y < 0 || y > (_cy - 101)) {

        _dy = -_dy;

        y += (2 * _dy);

    }

 

    // Move the ball to its new position

    _canvas.style.left = x + "px";

    _canvas.style.top = y + "px";

}

 

Animating the canvas position rather than animating the position of something within the canvas is a huge step in the right direction. And it has the added advantage that it allows the browser to use the GPU to move pixels around the screen – something the browser cannot do when your code is continually erasing and redrawing. Keep this in mind when building animations in HTML5.

A few weeks ago, I wrote about Silverlight for Windows Phone’s location API, which allows applications to ascertain their location – latitude, longitude, altitude (if GPS is available), and so on. More recently, I’ve been writing samples around HTML5’s geolocation API. The two APIs are remarkably similar save for HTML5’s lack of support for setting movement thresholds. Both allow you to write location-aware apps with remarkably little code, and both can be combined with Bing Maps to produce stunning UIs pinpointing a user’s location, providing turn-by-turn directions, and more. In fact, once you learn one of the location APIs, you’ll feel right at home with the other. They’re that much alike.

To demonstrate how to combine HTML5 geolocation with Bing Maps, I wrote a sample that I call MapLocation.html. Here it is in IE9, with a pushpin directly over my house:

BingMaps

Here’s the source code for the page, minus the Bing Maps API key that you must register for before using Bing Maps controls and services:

 

<!DOCTYPE html>

<html>

<head>

<style type="text/css">

body {

    margin: 0;

    height: 100%;

    background-color: #404040;

}

#map {

     position: absolute;

    top: 50%;

    left: 50%;

    width: 800px;

    height: 600px;

    margin-left: -400px;

    margin-top: -300px;

}

</style>

 

<script charset="UTF-8" type="text/javascript"

  src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0">

</script>

 

<script type="text/javascript" src="jquery.js"></script>

 

<script type="text/javascript">

    var _map;

 

    $(document).ready(function () {

        // Create a Bing map

        _map = new Microsoft.Maps.Map(document.getElementById("map"),

            { credentials: "Insert Bing Maps API key here" });

 

        // Get the current position from the browser

        if (!navigator.geolocation)

            alert("This browser doesn't support geolocation");

        else

            navigator.geolocation.getCurrentPosition(onPositionReady, onError);

    });

 

    function onPositionReady(position) {

        // Apply the position to the map

        var location = new Microsoft.Maps.Location(position.coords.latitude,

            position.coords.longitude);

        _map.setView({ zoom: 18, center: location });

 

        // Add a pushpin to the map representing the current location

        var pin = new Microsoft.Maps.Pushpin(location);

        _map.entities.push(pin);

    }

 

    function onError(err) {

        switch (err.code) {

            case 0:

                alert("Unknown error");

                break;

            case 1:

                alert("The user said no!");

                break;

            case 2:

                alert("Location data unavailable");

                break;

            case 3:

                alert("Location request timed out");

                break;

        }

    }

</script>

</head>

<body>

 

<div id="map" />

 

</body>

</html>

 

So how does it work? First, I point a <script> element to http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0, which is home for the new Bing Maps AJAX control, version 7.0. Then I instantiate a Microsoft.Maps.Map object (the map) and insert it into the DIV named “map.” Next, I call HTML5’s navigator.geolocation.getCurrentPosition to get the latitude and longitude of my current location. When that call completes, I call setView on the map control, passing in the latitude and longitude provided by getCurrentPosition. For good measure, I create a pushpin at the same location so my current location is called out on the map. Not a lot of code, but a WHOLE lot of results!

Here’s what I found most surprising about this exercise. Testing it on my desktop PC, I wasn’t sure if the geolocation API would work. Even if it did work, I expected the accuracy to be low since the location data would have to come from Wi-fi positioning. In most browsers, the accuracy is good to within a few hundred feet. In IE9, it’s so accurate, it pinpointed the location of the router in my house! Most browsers, I believe, use a positioning service provided by Google to convert IP addresses into locations. (I know that’s true of Opera, because the first time an app running in Opera requests a location, Opera pops up a dialog and asks you to agree to Google terms and conditions.) IE9 evidently uses something different, which isn’t surprising given that Microsoft probably wouldn’t care to make their flagship browser dependent on anything Google provided. Whatever Microsoft is using, it’s amazingly accurate. Of course, your mileage may vary.

It’s pretty cool to know that with HTML5, you can write browser-based apps that, for example, use your current location to show nearby restaurants, movie theatres, and stores. But what’s even more alluring is the thought of building mobile apps that work across a range of devices. If I use Silverlight for Windows Phone to write a location-aware app, it only works on Windows phones. But if I use HTML5, it should work on iPhones, iPads, and even on Android devices. Once Windows Phone 7 acquires an HTML5 browser, it’ll work there, too.

Even HTML5 doesn’t insulate you from all the annoying differences between browsers; I still find myself spending way too much time trying to get something that works fine in Firefox working in IE9, too, or vice versa. But the geolocation API is so simple that there’s not a lot to break going from one browser to another. That’s good news for developers, and good news for consumers as well.

One of the remarkable aspects of Windows Phone 7’s WebBrowser control is that you can build an entire Web site in isolated storage, point the WebBrowser control to it, and view the Web site on your phone. Once IE for Windows phones comes to support HTML5 (and that day can’t come soon enough, IMHO), this, I believe, will be a useful mechanism for packaging HTML5 apps so that they look and feel like native phone apps. Even now, using a WebBrowser control as a window into local HTML content provides a way to deploy HTML-based help systems to the phone. And I’m sure there are other uses for it that I haven’t thought of.

To demonstrate how to use WebBrowser to view locally stored content, I built a sample site in HTML and wrote the pages, images, and style sheets into isolated storage. Relative links allow the user to navigate among the pages. The home page looks like this:

WebBrowser

Here’s the HTML source for the page:

 

<html>

<head>

<meta name="viewport" content="width=480, user-scalable=yes" />

<link href="styles.css" rel="stylesheet" type="text/css" />

</head>

<body>

<img src="Images/BobCat.jpg" />

<h1>BVM BobCat</h1>

<p>Nullam fermentum tincidunt neque in fringilla...</p>

<a href="Page2.html">Next</a>

</body>

</html>

 

Notice the META element. It’s something you’ll almost invariably need if you build HTML content for Windows phones. If you remove the element, the page renders this way on the phone:

WebBrowser2

The META element provides a hint of sorts informing the WebBrowser control what the “native” width of the page is. I set it to 480, which is the width of the screen and the width of the image at the top of the page. With this element in place, the WebBrowser control happily sets the initial zoom level so that the page fills the width of the screen. Furthermore, the user-scalable=yes attribute indicates that the user should be able to zoom in and out using pinch gestures. To prevent users from zooming in and out, you can set this attribute to no.

There’s nothing complicated about <meta name=”viewport” content=”…” />, but if you don’t know that it exists, life with HTML on a Windows phone is measurably less pleasant.

I recently worked on a phone project that required me to tombstone a MediaElement control. Basically, I needed to save the current playback position when the app was deactivated, and restore it when (and if) the app was reactivated. So I whipped up something like this:

 

protected override void OnNavigatedFrom(NavigationEventArgs e)

{

    this.State["Pos"] = Player.Position;

}

 

protected override void OnNavigatedTo(NavigationEventArgs e)

{

    if (this.State.ContainsKey("Pos"))

    {

        Player.Position = (TimeSpan)this.State["Pos"];

        Player.Play();

    }

}

 

Unfortunately, it didn’t work. Each time the app was reactivated, playback started from the beginning. Investigation revealed that Position was being persisted in page state just fine. The problem was that the MediaElement seemed to be ignoring the Position I assigned to it in OnNavigatedTo.

That’s when it hit me. You can’t set a MediaElement’s position property when the MediaElement isn’t playing. And you’re not sure it’s playing until it fires a MediaOpened event. So one small change to the code solved the problem:

 

protected override void OnNavigatedFrom(NavigationEventArgs e)

{

    this.State["Pos"] = Player.Position;

}

 

protected override void OnNavigatedTo(NavigationEventArgs e)

{

    if (this.State.ContainsKey("Pos"))

    {

        Player.MediaOpened += (s, x) =>

            Player.Position = (TimeSpan)this.State["Pos"];

        Player.Play();

    }

}

 

Now the MediaElement picks up right where it left off before tombstoning. Good thing to keep in mind if you, too, find yourself needing to save and restore the state of a MediaElement.

One of the exciting new features coming in HTML5 – and one that works in most HTML5 browsers today – is Web storage. The latest draft of the specification defines two types of Web storage: local storage and session storage. Local storage, which is analogous to isolated storage in Silverlight, persists data across browser sessions, and does it purely on the client side. It provides an easy-to-use mechanism for storing arbitrary data on the client and is a cost-efficient alternative to cookies. Session storage, by contrast, persists data only for the length of the browser session. Session storage is useful for sharing data among pages hosted in the same browser window (it can’t span browser windows as local storage can), but I believe developers will generally find local storage more useful. One reason they’ll find it useful is that it offers a means for passing messages and data between browser instances – a freedom we’ve never really enjoyed without help from browser plug-ins such as Silverlight and Flash.

Local storage is accessed through the browser’s window.localStorage property. The following statements detect the presence of local storage support in the host browser:

 

if ("localStorage" in window && window["localStorage"] != null) {

    // Local storage supported

}

 

Not surprisingly, browsers are somewhat inconsistent in how they respond to this query. For example, if you run this code in IE9 in a page loaded from the file system, IE9 will report that it doesn’t support local storage. But load the exact same page from an HTTP URI and IE9 will provide local storage support just fine. Firefox 4 Beta 12 indicates that it supports local storage no matter where the page is loaded from, but it doesn’t persist local storage if the page is loaded locally. Chrome behaves in yet another way, happily supporting local storage (and persisting it) no matter where the page is loaded from. All three browsers support local storage and mostly do a fine job of conforming to spec, but as you’re testing, be aware that your local storage code might not work properly if you’re testing against FILE URIs.

Once you’ve ascertained that local support support is there, you can write to it using window.localStorage.setItem and read from it using window.localStorage.getItem. Local storage isn’t a repository for virtual files and directories as Silverlight isolated storage is; it can only hold key-value pairs. Furthermore, data is stringified when it’s written to isolated storage, so if you write an integer and read it back, you have to coerce it back to an integer. Simple types such as strings and numbers (and even arrays) can be written to local storage just fine, but for more complex types, you’ll need to serialize them with JSON.stringify and deserialize them with JSON.parse, or use a serialization library to do the same.

Here’s a simple example demonstrating how to write a string to local storage and read it back:

 

// Write to local storage

localStorage.setItem("language", "en-us");

 

// Read from local storage

var lang = localStorage.getItem("language");

 

Instead of calling setItem and getItem directly, you can use square brackets instead:

 

// Write to local storage

localStorage["language"] = "en-us";

 

// Read from local storage

var lang = localStorage["language"];

 

Here’s an example that persists an integer instead of a string. Note the call to parseInt to convert the string retrieved from local storage back to an integer:

 

// Write to local storage

localStorage["index"] = 0;

 

// Read from local storage

var index = parseInt(localStorage["index"]);

 

If you write a value to local storage and local storage contains an item with the same name, the new value overwrites the old. Similarly, if you try to read a nonexistent value from local storage, getItem will simply return null. You can also use removeItem to remove an item from local storage, or call the clear method to remove them all. Calling removeItem with a nonexistent key does nothing. Perhaps more importantly, it does not thrown an exception.

Data written to local storage is scoped per origin, where origin is the combination of scheme, host, and port. The page at http://www.wintellect.com/html5/Mandelbrot.html can access local storage written by http://www.wintellect.com/Scribble.html, but it can’t access local storage written by http://www.microsoft.com/html5/sample.html. Nor can it access data written to local storage by https://www.wintellect.com/html5/secure.html (notice the HTTPS at the beginning of the URI).

Browsers limit the amount of data that can be written to local storage by apps at a given origin, but the limits vary by browser. The HTML5 spec suggests a limit of 5 MB, but browsers aren’t compelled to comply. The spec doesn’t define an API for inquiring about remaining space, but if a write exceeds the quota, the browser throws a QUOTA_EXCEEDED_ERR error. Therefore, anytime you write to local storage, you should structure your code like this:

 

try {

    localStorage["language"] = "en-us";

}

catch (e) {

    if (e == QUOTA_EXCEEDED_ERR)

        window.alert("Storage quota exceeded");

}

 

Remember that this isn’t a per-app quota, but a per-origin quota. Your app might not have written anything to local storage, but if other apps from the same origin have already consumed the quota, your app won’t be able to write anything to local storage. And unlike Silverlight, HTML5 does not define any means for requesting a higher quota from the user.

One aspect of local storage that may surprise you is that it doesn’t work cross-browser. In other words, data written to local storage by a page running in Firefox can’t be read by the same page running in Chrome, and vice versa. Perhaps this shouldn’t be surprising, because every browser has its own unique way of implementing local storage. Still, Silverlight isolated storage works great cross-browser, and I had hoped that HTML5 local storage might offer the same capability. But no such luck.

If you’d like to see local storage in action, point your favorite HTML5 browser to http://www.wintellect.com/html5/storagescribble.html. Draw a few doodles on the chalkboard, and then close the browser. Restart the browser (the same browser, not a different one, since local storage doesn’t comport across browsers), and if your browser supports local storage, your doodles will reappear. As was true of the other Scribble tutorial I published recently, you can double-click the chalkboard to erase everything you’ve drawn.

Screen

Now, here’s the really interesting part – something that you can do with local storage that really has nothing to do with persisting data. Can you spell…interprocess communication?

In my Silverlight classes, I often demonstrate local connections by running two scribble apps side by side in different browser windows. As I draw in one window, my strokes appear in the other. Behind the scenes, I’m using a LocalMessageSender and a LocalMessageReceiver to fire messages from one browser to the other.

You can do something similar with local storage in HTML5. When a change is made to local storage – when an item is added, removed, or modified, or all the items are cleared – an HTML5 browser fires a storage event. You can register a handler for that event as follows:

 

window.addEventListener("storage", onStorageChanged, false);

  .

  .

  .

function onStorageChanged(e) {

    // Something changed

}

 

The sole parameter passed to the event handler is a StorageEvent object, which has properties named key, oldValue, newValue, and url, among others. These tell you what item changed and what its value now is. newValue is supposed to be null if the item was removed from local storage, and if all items were removed with a call to clear, key is supposed to be null. But the RC release of IE9 passes empty strings instead. This is important, because if your code only checks for null to detect removed items, you’ll get false positives in IE. Hopefully this will be fixed before IE9 ships.

More importantly, if there are two browser instances running and they’re hosting pages from a common origin, and one page modifies local storage in any way, the other page receives a storage event notifying it of the change! Consequently, we can use local storage events as a communications channel between browser instances. (Once more, IE9 behaves in a subtly different manner than other browsers. In Firefox and Chrome, if browser A modifies local storage, only browser B receives a storage event. But in IE9, both A and B receive storage events. This could break an app that writes to local storage and processes storage events, so be careful. You could argue that this is a feature and not a bug, because it could be used to couple two otherwise independent components running in the same application. The HTML5 spec isn’t clear about which behavior is correct.)

To demonstrate how to connect browser processes this way, I wrote a companion app for StorageScribble called ScribbleReceiver. Start StorageScribble from http://www.wintellect.com/html5/storagescribble.html, and ScribbleReceiver  from http://www.wintellect.com/html5/scribblereceiver.html. Be sure to run them in two browser windows. As you scribble in the first browser instance, your scribbles should be replicated in the second one. It works really well in Firefox and Chrome, and pretty well in IE9 except for the latency, which can be up to several seconds. Hopefully this, too, will change before IE9 is released.

image

I think developers are going to love local storage. It beats cookies hands-down when it comes to persisting state, and the fact that it can span browser instances opens up all sorts of possibilities, including a mechanism for detecting at startup when the app is already running in another browser. Think about it!

The last five years of my career have been devoted to Silverlight. I began working with it long before version 1.0 was released, and with Silverlight 5 on the horizon, I’m even more excited about it today than I was then. The fact that you can write phone apps with it is icing on the cake and the number one reason I’m bullish about Silverlight’s future and about the long-term prospects for Windows phones. I am honored and privileged to teach Silverlight and Silverlight for Windows Phone to Microsoft developers on campuses around the world, and every time I step into the classroom, I’m as excited and enthused as I was the very first time I pulled up a PowerPoint and said “Let me tell you how Silverlight is going to change your life.”

But while I was immersed in Silverlight, a funny thing happened: HTML5 came on like gangbusters. Microsoft and Apple execs seem to think HTML5 is the greatest thing since sliced bread. If you know me, you know how I feel about HTML and JavaScript. They’re fine for applets and Web pages, but building enterprise applications with them is another matter altogether. I’ll take C# any day over scripting languages. I like to be able to compile my code and make sure there are no syntax errors. I like to be able to test it and step through it in a debugger. JavaScript dev tools have come a long way in recent years, but they’re still a far cry from what you get out of the box with Visual Studio and C#.

HTML5 seems destined to play a huge role in the lives of software developers. It won’t be used just to build Web pages; it’ll be used to build browser-based applications, phone applications, applications for iPads and other slate devices, and yes, even enterprise applications. So I decided it’s time to dive in. Silverlight will still be my primary focus for the foreseeable future, but HTML5 will have a strong secondary focus. I’m scheduled to deliver my first HTML5 class on Microsoft’s Redmond campus in early April. I’m writing that course right now and am generally having a fun time doing it. Soon, it’ll be available to the public as well. And when people ask me how HTML5 compares to Silverlight, I’ll be able to offer a knowledgeable apples-to-apples assessment.

The feature of HTML5 that I find the most interesting and compelling is the canvas API. After all these years, developers are finally able to draw into a browser window without help from plug-ins. HTML5’s canvas API is reasonably well thought-out, and it even includes an equivalent to Silverlight’s WriteableBitmap, which allows apps to generate images on the fly and manipulate pixels destined for the frame buffer.

The starting point for HTML5’s canvas API is the new <canvas> element, which represents a pixel-addressable display surface. As a very simple example, suppose you wanted to draw a red rectangle into a browser window. You’d start by declaring a <canvas> element, and then write a bit of JavaScript to get a drawing context and call the context’s fillRect method:

 

// HTML5

<canvas id="output" width="400" height="400" />

 

// JavaScript

var canvas = document.getElementById("output");

var dc = canvas.getContext("2d");

dc.fillStyle = "red";

dc.fillRect(100, 50, 200, 100);

 

Of course, you can do much more than draw rectangles. You can draw lines, arcs, paths, text, images, and more. You can draw drop shadows, use alpha values, and apply transforms that are similar to the transforms you may be familiar with in XAML. You can perform pixel manipulations on what you’ve drawn, and you can use Boolean operators to composite shapes. In short, the canvas API is a rich one that opens the door to all kinds of interesting new HTML-only applications. And in the future, HTML will likely support 3D drawing operations as well as 2D operations. Imagine doing real 3D in the browser without any plug-ins!

To demonstrate key facets of the canvas API, I built a couple of samples and posted them on Wintellect’s Web site. The first is an HTML5 port of the venerable Visual C++ Scribble application from years ago:

Scribble

Use the left mouse button to draw, or double-click the chalkboard to clear it and start another masterpiece. If you’d like to try it out, point your favorite HTML5 browser such as IE9, Chrome, or Firefox 4.0 to http://www.wintellect.com/html5/scribble.html. I won’t reprint the source code here because you can see it for yourself with View Source. If you do, you’ll see that there’s not a whole lot to it. I used jQuery to handle mouse events because I didn’t want to have to write a boatload of code to make mouse handling work consistently in different browsers. And I used the little trick of assigning a value to a canvas’s width or height property to reset the canvas and erase everything in it.

The second example is an HTML5 Mandelbrot-set viewer. Here it is in Chrome:

Screen3 Screen4

It works in all three browsers, too, but IE9 doesn’t display the rectangular cursor used for zooming. If you run this app in IE9, you’ll have to imagine that the cursor points to the upper-left corner of a 100-by-100-pixel selection rectangle. The region inside the rectangle is what you’ll zoom into if you click.

The app is posted at http://www.wintellect.com/html5/mandelbrot.html. Once more, View Source is all that’s required to reveal the magic. This time I’m using HTML5’s createImageData and putImageData methods to generate bitmaps on the fly and display them in the browser.

Something that surprised me about the Mandelbrot app is the performance. The code that generates the fractal image loops through each and every pixel up to 128 times. Depending on the size of the browser window and the region of the Mandelbrot set you’re viewing, Chrome can take up to 3 or 4 seconds to render a new view, which isn’t bad considering the computational effort involved. Firefox, however, is astonishingly fast, typically generating an entire view in less than a second on my dual-core PC. This is a testament to how far JavaScript has come in terms of performance in modern browsers. Of the three browsers, IE9 is the least performant, often taking 5 seconds or more to render what Firefox renders in half a second.

Look for more blog posts in the future about HTML5 and how to leverage its most compelling new features.

Update: When I originally posted this article, I said that the sample apps don’t work in IE9. Turns out that was because I didn’t include the simplified HTML5 DOCTYPE element at the top of the files. Chrome and Firefox didn’t care, but IE9 cared greatly. The lesson is simple: when you author HTML5 pages, be sure to start them off with <!DOCTYPE html>.

Recently I have heard of a couple of cases in which apps submitted to the Windows Phone Marketplace were rejected because they continued running when an incoming phone call arrived. While the Windows Phone 7 Application Certification Requirements don’t specifically state than an application must pause when a call arrives, it seems that certain actions do trigger increased scrutiny from the certification folks. In one case, the app was rejected because it used the phone’s vibration controller and didn’t stop the vibration when the phone rang.

There is no specific API in Silverlight for Windows Phone for detecting incoming phone calls, but there is a pair of events in the PhoneApplicationFrame class named Obscured and Unobscured. Many developers mistakenly assume that these events are only raised when the screen locks and unlocks. In fact, they’re raised anytime your application is obscured by a piece of the UI shell, including when the phone receives a call. Regardless of whether your app is designed to run under a locked screen, you can use these events to make sure that your app behaves properly when it’s interrupted by a phone call or anything else that brings the shell to the foreground.

A page can register handlers for Obscured and Unobscured events through the application’s RootFrame property. The following code snippet registers handlers for both events and calls VibrateController.Stop when the application is obscured by the shell:

 

(Application.Current as App).RootFrame.Obscured += OnObscured;

(Application.Current as App).RootFrame.Unobscured += OnUnobscured;

  .

  .

  .

void OnObscured(object sender, ObscuredEventArgs e)

{

    VibrateController.Default.Stop();

}

 

void OnUnobscured(object sender, EventArgs e)

{

}

 

The Windows Phone 7 Application Certification Requirements do state that an application “must not delay or prevent the ability of the user to initiate a call, answer an incoming call, or end a call.” If you write an app whose actions could violate that dictum, use Obscured and Unobscured events to devise a fix.

Quick: can you spot what’s wrong with this XAML?

 

<ProgressBar x:Name="Progress" Visibility="Collapsed" IsIndeterminate="True" />

 

If you answered that setting IsIndeterminant to true on a ProgressBar control in Silverlight for Windows Phone debilitates performance, go to the head of the class! If not, read on.

If you use Silverlight for Windows Phone’s networking stack to download content or call Web services, you probably use the ProgressBar control a lot. If you’re downloading content with a WebClient, you may not use the ProgressBar’s IsIndeterminant property, because WebClient fires DownloadProgressChanged events that you can use to step the ProgressBar and keep the user informed about the progress of the download. But if you’re using HttpWebRequest to call REST services or Web-service proxies to call WCF services, you typically set the ProgressBar’s IsIndeterminant property true to display those running blue dots seen in applications such as Microsoft’s Facebook client for Windows Phone. It’s a nice thing to do from a UI perspective, because once you put a call on the wire, you have no control over how long it takes to complete. Rather than leave the user staring at a blank screen, the indeterminant ProgressBar lets the user know that you’re waiting for a network call to complete.

But there’s a problem. A ProgressBar running in indeterminant mode in Silverlight for Windows Phone sucks up CPU time. Worse, it sucks up CPU time on the UI thread rather than the dedicated composition thread, due to the creative way in which the control was implemented. Worse still, it continues to bang on the CPU even when the ProgressBar isn’t visible! More than one phone developer has noticed that his or her application is running slugglishly, traced it back to the presence of a ProgressBar, and wondered what the heck is going on.

Jeff Wilcox, a senior software developer at Microsoft, has documented this problem – and solutions – in an article entitled The High-Performance ProgressBar for Windows Phone and in a follow-up article. The recommended fix is to use Jeff’s PerformanceProgressBar control rather than ProgressBar. But at the very least, if you use the built-in ProgressBar, be sure to set IsIndeterminant to false anytime the control is hidden. I routinely do this now when launching an asynchronous network request:

 

// Show the progress bar

Progress.IsIndeterminate = true;

Progress.Visibility = Visibility.Visible;

 

And this when the call completes:

 

// Hide the progress bar

Progress.IsIndeterminate = false;

Progress.Visibility = Visibility.Collapsed;

 

One of the items on my to-do list is to go back and replace all my ProgressBars with PerformanceProgressBars. After all, a UI thread is a precious thing to waste.

Tombstoning is one of the greatest challenges in writing applications for Windows phones, which is why I decided to devote a series of blog posts to it. In Part 1 of this series, we built a photo-extras application that allows the user to perform simple image-editing chores on photos. In Part 2, we added tombstoning support so the application wouldn’t lose its state when tombstoned. And in Part 3, we fixed a bug in our tombstoning logic and refined it so that it wouldn’t untombstone anything if the app hadn’t been tombstoned in the first place. In this, the fourth and final article in the series, we’ll finally produce a finished application. But not before we squash one last bug – one that arises from an issue that’s unique to photo-extras applications.

First things first…we need to see the bug in action. To do that, you’ll need to deploy the application to your phone, because you can’t do what I’m about to do in the emulator. (Technically, that’s not quite true. The fundamental problem is that there is no Pictures library in the emulator, at least not one that you can see. There are undocumented ways to hack the emulator and unlock features that aren’t there by default, but I’m not going to get into that.)

Download the app to your phone. It’ll start up when you do. At this point, if you’re using the Zune client to connect your phone to your PC, close the Zune client. If you’re using WPConnect instead, you’re fine. WPConnect doesn’t prevent a phone tethered to your PC from accessing the media library, while the Zune client does. For more information, refer to Silverlight for Windows Phone Programming Tip #4.

Now, do the following:

  1. Press the Start button to go to the phone’s main screen.
  2. Tap the Pictures tile to open the pictures library.
  3. Select a picture. It doesn’t matter which one.
  4. Tap the ellipsis in the lower-right corner of the screen.
  5. In the ensuing menu, select “extras.”
  6. Select RealWorldTombstoningDemo to launch the sample app with the picture you just selected.

So far, so good. Now click the Open button in the application bar and select a different photo. Once again, it doesn’t matter which one as long as it isn’t the same one you selected a moment ago. You should now see the second of the two photos you selected. What do you see instead?

If you step through the OnNavigatedTo method in the debugger when the app is reactivated following the photo selection, you’ll see what’s happening. When RealWorldTombstoningDemo was launched, it was launched with a query string identifying a picture because it was launched from the “extras” menu.

When you clicked the Open button to select another photo, the app was deactivated. When you selected the photo, the app was reactivated. And here’s the key: because the app was originally launched with a query-string token, it’s reactivated with the query-string token, too. Rather than go through the code path that checks for a tombstoned bitmap, OnNavigatedTo followed the code path that loads a photo using a token. It’s as if the app was started from the “extras” menu a second time. But it wasn’t, so we need to ignore the token the second time and use the newly selected photo instead.

Now you see what I meant at the end of Part 3 when I said there’s still a major bug needing our attention. The good news is that it’s not difficult to devise a fix once you understand what’s happening. In a nutshell, we need to rewire OnNavigatedTo to do the following:

  1. If a photo is already present when OnNavigatedTo is called (which will be the case if a photo was loaded in OnPhotoSelected or the app was deactivated but not tombstoned), do nothing.
  2. If there’s no photo present (in other words, if _bitmap == null), check to see if there’s a photo awaiting untombstoning. If there is, untombstone it.
  3. If there’s no photo present and nothing to untombstone, check to see if there’s a query-string containing a picture token. If there is, load the photo from the token.

Here’s the finished OnNavigatedTo method. It’s not very different than before; it has just been restructured a bit. Basically we now give an existing bitmap precedence over one loaded from the “extras” menu. And we retain the key if _bitmap == null test that prevents us from untombstoning a bitmap if a bitmap is already present.

 

protected override void OnNavigatedTo(NavigationEventArgs e)

{

    Debug.WriteLine("OnNavigatedTo");

 

    if (_bitmap == null) // Skip this if a bitmap is already loaded

    {

        // Restore the state of the Save button

        if (State.ContainsKey(_save))

            (ApplicationBar.Buttons[1] as ApplicationBarIconButton).IsEnabled =

                (bool)State[_save];

 

        // Restore the WriteableBitmap

        if (State.ContainsKey(_width) && State.ContainsKey(_height))

        {

            int width = (int)State[_width];

            int height = (int)State[_height];

 

            // Create a new WriteableBitmap

            _bitmap = new WriteableBitmap(width, height);

 

            // Get the bitmap bits from isolated storage

            using (IsolatedStorageFile store =

                IsolatedStorageFile.GetUserStoreForApplication())

            {

                if (store.FileExists(_file))

                {

                    using (IsolatedStorageFileStream stream =

                        new IsolatedStorageFileStream(_file, FileMode.Open, store))

                    {

                        using (BinaryReader reader = new BinaryReader(stream))

                        {

                            int count = _bitmap.Pixels.Length * sizeof(int);

                            byte[] pixels = new byte[count];

                            reader.Read(pixels, 0, count);

                            Buffer.BlockCopy(pixels, 0, _bitmap.Pixels, 0, count);

                        }

                    }

 

                    // Clean up by deleting the file

                    store.DeleteFile(_file);

                }

            }

 

            // Show the bitmap to the user

            Photo.Source = _bitmap;

        }

        else if (NavigationContext.QueryString.ContainsKey("token"))

        {

            // If the app was invoked through the Extras menu, grab the photo and display it

            MediaLibrary library = new MediaLibrary();

            Picture picture =

                library.GetPictureFromToken(NavigationContext.QueryString["token"]);

 

            BitmapImage bitmap = new BitmapImage();

            bitmap.SetSource(picture.GetImage());

            _bitmap = new WriteableBitmap(bitmap);

            Photo.Source = _bitmap;

 

            // Disable the application bar's Save button

            (ApplicationBar.Buttons[1] as ApplicationBarIconButton).IsEnabled = false;

        }

    }

}

 

Now, believe it or not, we have a finished app. You can download it and see for yourself. Try to trick it: load photos, click buttons, play taps on the Back button, launch from the “extras” menu, and anything else you can think of. Unless I’ve missed something, this app is ready to ship.

I did slip one additional feature into the final version. Before, if you edited the photo (clicked it to convert colors to grays) and clicked the Back button, you exited the app with unsaved data. Because the app is closed (not tombstoned) when you exit with the Back button, the changes are lost forever. That’s not a big deal for a demonstration app, but it could be a very big deal in one with richer editing features. So I added an OnBackKeyPress method that prompts the user for confirmation before exiting with unsaved changes:

screen

Check the source code to see how it works.

More Posts Next page »