XAML -- Almost A Full Blown Language

11/7/2003 12:02:21 PM

XAML -- Almost A Full Blown Language

In a prior post, I mentioned XAML's tight relationship to .NET, even tighter than its raison d'etre, which is to be a declarative method of specifying a user-interface. This is a major difference fromother UI markup languages and is a good example of the high level of abstraction that Avalon APIs are aiming for. (There is a general belief in Microsoft that APIs should not impose unnecessary restrictions; each restriction decreases the number of features provided by the platform and can limit the future extensibility of the OS. For instance, in Avalon, most controls such as TreeViews, ListBoxs and Menus can contain arbitrary subcontrols, not simply just strings as in Win32.)

Since then, the secret has come out and Don Box has implemented a console app in XAML.

This illustrates that XAML is a declarative method of describing any tree of .NET objects. It is domain-neutral, as Don puts it. The trick is to override the default namespace settings with a new XML processor instruction <? Mapping ?>. Via this technique, you might be able to describe a user interface in WinForms.

Let me give an example. Assume we write XAML like the following:

<?xml def:Class="MyClass" ?>
<?Mapping ... >
<Class SimpleProperty="Hello" EnterEvent="MyEvent">
   <Class.ComplexProperty  SubProperty="True" >
       <Class2 ID="child" />

We would need a class like this defined in some assembly that we reference through the Mapping instruction:

public class Class
     public string SimpleEvent;
     public ComplexType ComplexProperty;
     public IList Items { get; }
     public event Event EnterEvent;

The XAML is transformed into the following code, using a number of rules.

public class MyClass
   public Class2 child;
   public MyClass()
       Class obj = new Class();
       obj.SimpleProperty = "Hello";
       obj.ComplexProperty = new ComplexProperty();
       obj.ComplexProperty.SubProperty = True;
       Class2 obj2 = new Class2();
       child = obj2;

The XAML compiler uses reflection to determine what is the appropriate code to generate.

The top-level element corresponds to an instance of a class sharing the same name as the element.

Each attribute corresponds to a member of the class. If the member is property, that property will be assigned the attribute's value; the property may be a regular CLR property or a dependency property. If the member is a event, a new delegate will be create and added to point to the function specified by the attribute. The function must be an instance method of the top-level object and can exist either in a def:Code element within the XAML or within the code-behind file. XAML also includes extensions for Avalon's UI to handle attached properties--properties defined by unrelated objects and attached to the current object.

Since attributes can only be string values, the standard .NET mechanism of using TypeConverters is used to map a string to another type and backwards. The standard types like bools, enums and integers already have TypeConverters declared. In .NET, TypeConverters are classes that provide conversion from an arbitrary type to a specific type; these are more general than the IConvert interface and are used by Visual Studio's property grid to query control properties and render than appropriately for arbitrary objects like fonts and colors. XAML calls TypeDescriptor.GetConverter(typeof(type)) and then a function like ConvertFrom(context, obj).

Subelements are added to the object through a number of means. The most common of which is via the IAddChild interface, which, if defined by the object, contains two methods (AddChild and AddText), but if a property supports an IList instead, the Add method of that collection property will be called, I believe. A subelement of the form "Class.Property" represents a complex property, which are properties of a type that can't adequately be expressed in a string form. For each property, you have a choice of using the complex or simple form, so it's not all or nothing.

In addition to all this, XAML supports special elements and attributes for XML data islands, resources, inline code (as well as code behind), and special syntax for data binding--which I believe can all be used with custom namespaces.

What's missing? XAML does not have a notion of functions or macros, that allow a complex piece of XAML to be repeated and be slightly modified within the same file. For that, you need to use XSLT.

Update: There is an MSDN TV video that illustrates this capability within XAML.






Net Undocumented is a blog about the internals of .NET including Xamarin implementations. Other topics include managed and web languages (C#, C++, Javascript), computer science theory, software engineering and software entrepreneurship.

Social Media