Welcome to WindowsClient.net | Sign in | Join

Rob Relyea - Xamlified

WPF, Silverlight and Xaml

Syndication

Sponsors





  • advertise here
Strings to Things (or How XAML interprets Attribute Values)

I don't know who said it first on our team during construction of the first XAML based system...perhaps Mike Hillberg, but XAML's common use is to convert "strings to things"...our treatment of the strings in attribute values plays a big part in that.

Supporting a TextSyntax for properties

[MS-XAML] Xaml Object Mapping Specification 2006 says that any XamlType or XamlProperty in a XamlSchema can have a TextSyntax.  Fundamentally, that allow us to represent complex objects like <SolidColorBrush Color="Red" /> as just "Red".  Let's look at some examples...

.Net TypeConverters and XAML

In full .Net and Silverlight, you can think of TextSyntaxes as mapping to TypeConverters.

<Button Background="Red" /> is the snippet I often start with when discussing XAML.  Of course, the story of how we treat "Red" is one of the key things to learn about XAML.

A Type Converter Declared on a Type

In WPF, the Background property on Button is of type Brush and Brush has an associated TypeConverter called BrushConverter:

[TypeConverter(typeof(BrushConverter))]
public class Brush
{
...
}

XAML:

<Button Background="Red" />

So when we are loading that snippet of XAML; it means

Button b = new Button();
b.Background =
    new BrushConverter().ConvertFromString("Red");

Best practice for code programmers is to do:

Button b = new Button();
b.Background = Brushes.Red;

To somebody wearing XAML colored glasses, in .Net, the job of a TypeConverter is to enable strings to map to/from the right instance value.

A Type Converter Declared on a Property

Usually, when building a Type, you want to use a preexisting Type as the ValueType for a Property you are defining. Sometimes you'd like to make the XAML representation of that type special; you'd like to override the type converter declared for that Type.

In WPF, the Height property on UIElement is of type Double.  However, we don't want people to always have to talk in pixels, we'd like to be able to support units like "in" and "cm" as well.

public class UIElement //fyi: Button is a UIElement...
{
    [TypeConverter(typeof(LengthConverter))]
    public double Height
    {
    }
}

XAML:

<Button Height="2in" />

That ensures that loading of  will mean:

Button b = new Button();
b.Height=
    new LengthConverter().ConvertFromString("2in");

Best practice for code programmers is to do:

Button b = new Button();
b.Height = 2 * 96; //regardless of your DPI, WPF treats 96 pixels as 1 inch.

How about Attachable Properties

For an attachable property that is defined by a type, XAML looks at the static getter for any attributes such as TypeConverterAttribute.

public class Canvas
{
    [TypeConverter(typeof(LengthConverter))]
    static public GetTop(UIElement) {...}
    static public SetTop(UIElement, double) {...}
}

Note: I've started calling properties which a class defines as "Attachable" and actual uses of it as "Attached"

How about Enums

XAML:

<Button HorizontalAlignment="Center" />

XAML to Object treats this as:

Button b = new Button();
b.Background =
    new EnumConverter(typeof(HorizontalAlignment)).ConvertFromString("Center");

Coding best practice:

Button b = new Button();
b.Background
    HorizontalAlignment.Center;

How about Flags Enums

If you have an Enum that is Flags, meaning you can "or" together several values, XAML uses the EnumConverter as normal.

If MyType has a MyProperty property of MyEnum type...

XAML:

<MyType MyProperty="A,B" />

XAML to Object treats this as:

MyType t = new MyType();
t.MyProperty =
    new EnumConverter(typeof(MyEnum)).ConvertFromString("A,B");

Coding best practice:

MyType t = new MyType();
t.MyProperty = MyEnum.A | MyEnum.B;

In WPF, ModifierKeys overrides that default behavior to support "+" instead of "," as its delimeter so one can say: "Ctrl+Alt".  I always forget which delimiter is used by the EnumConverter, so that is why I started this blog post...it just grew a bit.

How about Nullable<Foo>

When a property is a Nullable<T> type, such as Nullable<double>, XAML uses the double type converter.

Types in MsCorLib

A strange thing about .Net is that TypeConverter and TypeConverterAttribute is defined in System.dll, but most of the very primitive types like String, Double, Int32 are in mscorlib.  Since System.dll references MsCorLib.dll, MsCorLib couldn't decorate its types with the TypeConverterAttribute.  Some systems use TypeDescriptor (from my memory) to map types to their type converters, XAML hard codes knowledge of how to find the right type converters for mscorlib types, and then follows the rules described above (looks for type converters on properties first, then the type).

Notes about Silverlight 2 and XAML

Silverlight 2 has this same mapping to TypeConverter for Property or Types for your custom types.  As of beta1, most, if not all, built in types don't have the TypeConverterAttribute decorated on it, instead the XamlReader has hard coded knowledge of how to convert strings to instances, much like .Net's XAML parser hard codes knowledge for MsCorLib types.

Why TypeConverters

Our philosophy during WPF 3.0 development was to try to leverage as many CLRisms as possible and only invent new concepts when necessary.  TypeConverterAttribute was a .Net 1.0 feature which associates a TypeConverter class with a type.  TypeConverters aren't perfect, for instance given a specific instance of a Brush, they can't tell me if they will have a text representation for it.  We build ValueSerializers in .Net 3.0 to add that ability.  A topic for another day...

Danger of complex TextSyntaxes (often referred to as MiniLanguages)

Be careful about building complex logic in your type converters...humans and tools need to understand what TextSyntaxes are possible.  In WPF's development, we ended up removing several text syntaxes during development because they were partial solutions...we didn't want to lead users down a path that was a dead end.

One example of that was the fact that BrushConverter supported a special syntax to support LinearGradientBrushes. "HorizontalGradient Blue White" was equivalent to this Property Element syntax:

<LinearGradientBrush>
    <GradientStop Color="Blue" Offset="0" />
    <GradientStop Color="White" Offset="1" />
</LinearGradientBrush>

The problem with that syntax is that it only supported 2 GradientStops, it supported Horizontal or Vertical gradients, but not diagonal.  You could imagine that we could have invested a bunch of time to build a string based language for that.  But we didn't need to!  We could just say...let's keep it simple.  If it isn't simple, people should go use tags anyway...

Expressing types with TypeConverters as Elements

If a type does have a TypeConverter, it may specified as a Tag, even if the Type is abstract.  <Brush>Red</Brush> will work.  You need to avoid setting properties on the Brush itself (in XAML).  We do allow x:Key attributes, so you can place the brush in a dictionary, etc...

Related Articles/Blogs

Published Thursday, April 10, 2008 5:06 AM by Rob_Relyea

Comments

# Pages tagged "msdn"@ Thursday, April 10, 2008 2:49 PM

Pingback from  Pages tagged "msdn"

# Simple way to create a gradient brush in Xaml@ Friday, April 25, 2008 2:09 AM

Rob , Nikhil &amp; I were talking today about the early days of Xaml when you could create linear gradient

# Simple way to create a gradient brush in Xaml : Silverlight@ Saturday, May 31, 2008 12:16 PM

Pingback from  Simple way to create a gradient brush in Xaml : Silverlight

# Automatically stretching a Silverlight 2 control on a webpage &laquo; An Original Idea@ Monday, June 02, 2008 7:48 PM

Pingback from  Automatically stretching a Silverlight 2 control on a webpage &laquo; An Original Idea

# Simple way to create a gradient brush in Xaml | Silverlight@ Thursday, June 05, 2008 1:23 PM

Pingback from  Simple way to create a gradient brush in Xaml | Silverlight

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Page view counter