New in the Silverlight 4 RC: XAML Features

Today, the Silverlight 4 RC was announced and made available to the masses.  But you may be asking yourself: what’s new since the beta?  Well, I’d like to dive into one of the areas where a bunch of new work was done to improve the development experience – the XAML Parser.  With Silverlight 4, we’ve done a significant overhaul of the XAML Parser, allowing us to add new features and improve consistency within the platform and with WPF’s XAML support.

So, let’s take a quick walk through some of the new things you can do with Silverlight XAML as of the RC!  This is by no means an exhaustive list, but it’s definitely some of the bigger items.

Direct Content

This is one of those small inconsistencies with WPF that people hit almost immediately when they try to write Silverlight XAML after moving over from the WPF world.  Specifically, things like this now work in Silverlight:

<Button>Click me!</Button>

I know, I know – exciting, right!?  In Silverlight 3, you had to use attribute syntax or explicitly surround “Click Me!” in a string, like this:

<Button Content="Click me!" />

or…

<Button xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <sys:String>Click me!</sys:String>
</Button>

I know when I first made the move from WPF to Silverlight, this was among the most irksome and frustrating things about its XAML parser.  With Silverlight 4, that frustration is gone, and I can enjoy direct content in my controls once again!

See the image below for more examples:

A quick demo of direct content support in Silverlight 4 XAML.

xml:space=”preserve”

In previous versions of Silverlight, the XAML parser was rather liberal about how it applied whitespace.  In general, it didn’t discard extra whitespace as most XML parsers will.

For example, the following XAML:

<TextBlock>
    <TextBlock.Text>This
Text
Is
On
Separate
Lines
    </TextBlock.Text>
</TextBlock>

Looked like this:

Whitespace preservation in prior versions of Silverlight.

The XAML parser in Silverlight 4 has finally corrected this behavior, and has also added support for xml:space=”preserve”.

When you recompile your application with the Silverlight 4 RC, the same XAML will produce the following:

image 

To get back the old behavior, add xml:space=”preserve” to your XAML:

<TextBlock xml:space="preserve">
    <TextBlock.Text>This
Text
Is
On
Separate
Lines
    </TextBlock.Text>
</TextBlock>

Finally, you have control over your whitespace back!  The results are much more predictable, and you can now be explicit about what you want the text content to be.

Please note: when you upgrade your application to Silverlight 4 (i.e. recompile for Silverlight 4), you’ll need to watch out for this change!

ISupportInitialize

If you were a fan of the ISupportInitialize interface in the full framework, it’s finally made its way into Silverlight!  The XAML parser in Silverlight will now call ISupportInitialize.BeginInit() and ISupportInitialize.EndInit() on your classes (if you implement the interface) before and after setting properties defined in XAML.  This allows you to wait to do work until after all of your properties have been set, allowing you to handle properties that would otherwise be order-dependent and add some validation that combinations of properties are valid.

It’s a convenient and welcome functionality to have around, especially for those of us that like declarative programming and are happy to use XAML as our format for doing so!

XmlnsDefinition attribute

In Silverlight 3 and earlier, how many times did you find yourself in a situation like this?

<UserControl x:Class="SilverlightApplication1.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
             xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
             xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input"
             xmlns:navigationMappings="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
             xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
             xmlns:ohmygoshtherearetoomanyofthese="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400">...

And that’s just with some of the SDK assemblies!  Declaring xmlns’s in your XAML was a chore, and it was extremely easy to end up with a huge mess of them, as they require one definition per namespace/assembly.  Add in the toolkit controls and any custom libraries, and you’re easily looking at 20 lines of these definitions.  This is more than just a problem of convenience – it makes XAML intellisense a big problem as well.  Visual Studio starts its intellisense experience by waiting for an xmlns to be entered, such as “input:”.  Within that namespace, it will filter your options to valid tags for your context within the XAML.

But, if you’re like me and like to break your libraries up into small pieces, this is not very helpful – I have to remember exactly which xmlns has which set of things that derives from the type I’m trying to create in XAML, and if I got it wrong, there’s not much there to help me.

Silverlight 4 adds support for the XmlnsDefinitionAttribute in custom assemblies, and the SDK has been updated to take advantage of this.  Now, you can replace all of the code above with this:

<UserControl x:Class="SilverlightApplication1.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400">...

Likewise, with the next update of the Silverlight Toolkit, you will likely see a similar change, allowing you access to all referenced toolkit controls from one xmlns!  Phew!  What a relief!

With that in mind, I’ve also updated SLaB to use XmlnsDefinitionAttribute, which really helps clean up the use of those libraries with Silverlight 4.

This is one of my favorite features, if only because it makes working with XAML so much simpler in Visual Studio, and now it’s available for you and other control/XAML-centric developers to use in your libraries as well!

Xmlns flexibility

Silverlight 3 required that your default namespace always be the following:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

This was sometimes irritating when you wanted to use XAML as a serialization format for something other than UI, since you had to preface every element with some other xmlns.  In Silverlight 4, you can now change the default xmlns namespace at will, which you can use to clean up your XAML and customize your serialization format as you wish.

Custom IDictionary support

In XAML, it’s supposed to be possible to add items to a dictionary just as you would a list by using the “x:Key” attribute.  In prior versions of Silverlight, the only case where this was allowed was when used inside of a ResourceDictionary.

With Silverlight 4, anything that implements IDictionary can be used in XAML.  To this end, I’ve provided a simple BindableDictionary in my SLaB libraries that you can now use like so (although you could just as easily use a Dictionary<object, SomeType> or a custom implementation of IDictionary):

<SLaB:BindableDictionary x:Key="ValueBag"
                                xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <sys:Double x:Key="Value Between Zero and 100">37.9184273</sys:Double>
    <sys:Boolean x:Key="A boolean">True</sys:Boolean>
</SLaB:BindableDictionary>

This is extremely useful for more complex XAML scenarios where you want a Dictionary rather than a List to be declared in XAML.  One example I’ve been wanting to play with: an INavigationContentLoader (it’s an obsession – I’m sick, I know :)) that maps a protocol (e.g. http:// or pack://) to another INavigationContentLoader, allowing protocol-specific content loading within a single application.

Non-DependencyProperty Attached Properties

Although you’re probably used to seeing them as such, attached properties are actually completely separate from DependencyProperties (just as properties are distinct from DependencyProperties).  In order to style or bind to them, they must be DependencyProperties.  Otherwise, it’s just an API convention:

using System.Collections.Generic;
using System.Windows.Controls;

namespace SilverlightApplication1
{
    public class ClassWithAttachedProperty
    {
        private static Dictionary<Grid, int> values = new Dictionary<Grid, int>();
        public static int GetGridMetadata(Grid g)
        {
            return values[g];
        }
        public static void SetGridMetadata(Grid g, int someValue)
        {
            values[g] = someValue;
        }
    }
}

Which can then be used in XAML like so:

<UserControl x:Class="SilverlightApplication1.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:my="clr-namespace:SilverlightApplication1">
    <Grid x:Name="LayoutRoot" my:ClassWithAttachedProperty.GridMetadata="150">
    </Grid>
</UserControl>

Note: I don’t recommend keeping a dictionary of Grid—>int around :).  That’s a giant memory leak waiting to happen!  It’s just convenient for demonstrative purposes.

Better error messages

One of the biggest complaints about XAML in Silverlight has been its poor reporting of errors when you’ve done something wrong.  This should have significantly improved in Silverlight 4.  In general, you’ll get more context and much clearer error messages at runtime when you make a mistake in XAML.  In general, that feeling of “what the heck just happened?” should be lifting when it comes to working with XAML.  It’s still not perfect, but things have improved significantly.

Wow, that’s a lot of stuff!

Yep, there’s been plenty of change with the parser, and the improvements should lead to a better experience when doing declarative development using XAML in Silverlight!  Please let me know what you think!  What’s your favorite feature or biggest peeve?

What about SLaB?

I’ve updated SLaB for the Silverlight 4 RC.  There’s a bunch of new stuff in there that I hope to blog about soon.  In the meantime, here’s a snippet from the changelog:

  • For the latest version, please check out SLaB on my Downloads and Samples page.
  • The v0.4 download of SLaB includes the following changes:
    • Added ZipUtilities so that the contents of a zip file can be discovered
    • Updated XapLoader to use ZipUtilities, allowing all TPEs to work rather than being limited to single-file TPEs where the file is named the same as the zip
    • Added Sitemap-based controls: BreadCrumbNavigator and TreeViewNavigator
    • Added ChangeLinq libraries for working with INotifyCollectionChanged collections and LINQ
    • Added ObservableDictionary and BindableDictionary, which raise INotifyCollectionChanged and INotifyPropertyChanged events as the dictionary changes, making it more usable with Binding
    • Added a basic MEFContentLoader
    • Updated to use XmlnsDefinitionAttribute wherever possible
    • Added XmlnsDefinition attributes to all libraries and updated ScratchApplication to use them
    • Other minor bugfixes

Enjoy, and let me know if you have any questions, thoughts, or ideas!

Remember, SLaB is just a collection of the samples and experimental components I’ve been putting together so that they’re all in one place.  I can’t make any guarantees about maintaining them, fixing bugs, not making breaking changes, etc., but you’re more than welcome to try them out, use them, and let them inspire your development (or show you what not to do if you really dislike something I’m doing!) :) .

21 thoughts on “New in the Silverlight 4 RC: XAML Features”

    1. This work does have a fair amount in common with System.Xaml, at least in that it helps bring Silverlight’s parsing closer to what is being done in .Net 4.0. For now, Silverlight XAML remains a subset of what you can do in .Net 4.0, but this work does lay the foundation to make future moves toward some sort of convergence (or an increase in features on the Silverlight end). I can’t make any promises or firm statements about what (if anything) you might see in the future, but if there are particular things you’re missing from Silverlight XAML, I’d love to know what they are :)

  1. We are developing an application which has both Silverlight and WPF versions.We are facing a big issue in resuing the xaml.

    In Silverlight the x:Class attribute expects full qualified name(With namespace)
    In WPF the x:Class expects only the class name.If we give namespace it will show error.

    That means we are now not able to share the xaml.Please help to resolve this issue..

    We are using .Net 4.0 and Silverlight 4.0 Beta with VSTS 2010 Beta 2.

    Thanks
    Joy

  2. The discription from xml:space=”preserve” is inside out.

    xml:space=”preserve” gives the new behavior, without it works like in SL3

  3. Hi. How can someone reuse the MEFContentLoader in both xaml and button event.
    Supposing i am using content frame link buttons in the convention Silverlight Business tamplate.
    thanks.

  4. Hi David – Thanks so much for your awesome blog and code samples.

    I pulled down the SLaB source and am trying to get it up and running (specifically the printing controls) and am running into the following issue:

    Line: 54
    Error: Unhandled Error in Silverlight Application
    Code: 2152
    Category: InitializeError
    Message: Failed to download a platform extension: SLaB.Printing.Controls.zip

    Are there any notes on getting started, or something simple I’m missing?
    Thanks!
    -David

    1. David,

      This looks like you’re missing the .zip file in your ClientBin directory (or wherever you’re pulling your XAP from). When you turn on assembly caching in VS, it should be putting these zip files in the right place for you. Assuming you’re using an ASP.NET web project, check to see that your ClientBin contains the SLaB.Printing.Controls.zip file.

      -David

  5. Hi again, and thanks for your prompt answers!

    I found what looks like a small bug in the printing control and just wanted to give you a heads up. If I click the print button but then cancel the dialog, and print again, I get the following Exception (presumably it’s not printing if I cancel it?):

    Cannot print two things at once

    at SLaB.Printing.Controls.CollectionPrinter.Print(PrintDocument document)
    at SLaB.Printing.Controls.CollectionPrinter.Print()
    at SLaB.Printing.Controls.CollectionPrinter.b__0(Object param)

  6. The plot thickens… it seems like PrintDocument.EndPrint event doesn’t fire if one cancels out of the print dialog after initiating a Print command.

    Steps to reproduce:
    Click ‘Print’ on the datagrid demo page
    Click Cancel in the print dialog
    Click ‘Print’ again > Get the exception

    Steps to not reproduce :)
    Click ‘Print’ on the datagrid
    Choose a printer/XPS and print the document
    Click ‘Print’ again and it will work, since it got the EndPrint event.

    Here’s the same question on stackoverflow:
    http://stackoverflow.com/questions/3803967/capture-print-dialogs-cancel-in-silverlight-printing

  7. We’ve been trying to implement several silverlight technologies into our custom software without much luck…any recommended developers to outsourcing such a task too?

Leave a Reply