Windows Store-apps: WinRT XAML vs. Silverlight XAML
This post is part of a series about creating Windows Store-apps with XAML and C#. Find the Content of the series here:
Windows Store-apps with XAML and C# blog-series
Last weekend I’ve finished the XAML-chapter of my upcoming book about developing Windows Store-apps with XAML and C#. I want to share the things that you should know about the WinRT XAML – the way I call it here - if you’re familiar with Silverlight or WPF.
The WinRT XAML is much like the XAML we know from Silverlight. But there are some differences in WinRT XAML:
- the way you use your custom namespaces is different
- there are some missing things (TypeConverters, Custom MarkupExtensions)
Use custom namespaces
There are two ways in XAML to use a namespace:- 1:1-Namespace-Mapping
- 1:n-Namespace-Mapping
The 1:1-Namespace-Mapping
Let’s assume you’ve the following class:namespace UIRocker.Special
{
public class WindowsEight
{
public bool IsGreat { get; set; }
}
}
To use this class in Silverlight-XAML, you’ve to add an Namespace-Mapping like this
xmlns:rocker="clr-namespace:UIRocker.Special"
or like this if the CLR-Namespace is in another assembly than the XAML-file containing the Namespace-Mapping below:
xmlns:rocker="clr-namespace:UIRocker.Special; assembly=UIRockerLib"
With the Namespace-Mapping the classes from that Namespaces can be used with the chosen alias. The alias is “rocker” in the snippets above, so the WindowsEight-class can be used as below:
<rocker:WindowsEight IsGreat="True"/>
In WinRT-XAML you’re using the class in the same way as above, but the way of creating the Namespace-Mapping is different. Instead of using the syntax with “clr-namespace…” you use:
xmlns:rocker="using:UIRocker.Special"
You don’t care if the Namespace UIRocker.Special is in another assembly as the XAML-file or not. This works exactly the same way as the using-directive in C#, where you also don’t care if the Namespace is in another assembly than the .cs-File or not. So, great improvement, but creates a little incompability with Silverlight-XAML.
The 1:n-Namespace-Mapping with XmlnsDefinition-Attribute
The Namespace-Mappings above have been 1:1-Mappings. One XML-Namespace was mapped to one Silverlight/WinRT-Namespace. In Silverlight-XAML you can create a 1:n-Namespace-Mapping by placing the XmlnsDefinitionAttribute (Namespace: System.Windows.Markup) on your assemblies like this:[assembly: XmlnsDefinition(
"http://thomasclaudiushuber.com/","UIRocker.Special")]
[assembly: XmlnsDefinition(
"http://thomasclaudiushuber.com/", "UIRocker.Mvvm")]
Classes out of the Namespaces UIRocker.Special and UIRocker.Mvvm can be used in XAML with one alias by making a 1:n-Namespace-Mapping like this:
xmlns:rocker="http://thomasclaudiushuber.com/"
Unfortunately in WinRT-XAML there is no possibility for a 1:n-Mapping. The Namespace Windows.UI.Xaml.Markup contains a XmlnsDefinition, but it’s not an attribute, it’s a struct and therefore not usable.
Especially when you create a library with many Namespaces in it, it’s great to use just one alias for the library in XAML. Maybe the next Version of WinRT will contain such a mapping. By the way, first versions of Silverlight also didn’t support 1:n-Namespace-Mappings.
Missing things in WinRT-XAML
There are a few other things that are not in WinRT-XAML or behave differently. Let’s take a look at them.Typeconverters
As XAML is XML, every Attribute contains a string-value. This string-value needs to be converted into the value of the property-type the attribute represents. For primitive types like double, float, int, bool, char etc., the conversion automatically is done by the XAML-Parser (Silverlight and WinRT). Also for Properties of type enum, the XAML-Parser tries to convert the specified string-value into the enum-type of the property. There is also a conversion for some central types hardcoded in the XAML-Parser of Silverlight and WinRT, e.g. the Brush-Type. This conversion allows you to assign a string in XAML where a Brush-Instance is required:<ListBox Background="Red">
The XAML-Parser takes the “Red”-string, creates a SolidColorBrush with the Color Red and assigns it to the Background-property of the ListBox.
(Excourse to WPF-XAML: In WPF-XAML this conversion is not done by the XAML-Parser, it is done by the BrushConverter-class)
Now if you have properties that are of your own type, let’s look at this works in Silverlight and WinRT. Let’s assume we have the classes below:
public class Person
{
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
public string Country { get; set; }
}
In Silverlight-XAML, it is possible to create a Person-instance as below if a TypeConverter for the Address-type exists:
<local:Person Address="Müllheim Germany"/>
The corresponding typeconverter could look like this:
public class AddressConverter : TypeConverter
{
public override bool CanConvertFrom(...Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(...object value)
{
if (value != null && value is string)
{
var array = value.ToString().Split(' ');
if (array.Length != 2)
throw new ArgumentOutOfRangeException(
"Invalid format for address");
return new Address
{
City = array[0],
Country = array[0]
};
}
return base.ConvertFrom(value);
}
}
The only thing that is additionally required is to tell the XAML-Parser where to find the AddressConverter. You do this by specifying the TypeConverterAttribute either on the Address-Property in the Person-class or on the Address-class itself. Below an example that specifies it on the Address-class.
public class Person
{
public Address Address { get; set; }
}
[TypeConverter(typeof(AddressConverter))]
public class Address
{
public string City { get; set; }
public string Country { get; set; }
}
So far to Silverlight-XAML, now let’s look at WinRT-XAML. As mentioned above, WinRT-XAML also supports conversion for
- primitive Types like bool, char, double, int, float,…
- enumeration-values
- central types like e.g. the Brush-type.