Site Logo

Pixel-in-Gene

Exploring Frontend Development with Design / Graphics / Technology

Instantiating a custom object-tree in XAML

XAML, which is short for eXtensible Application Markup Language is a great tool for instantiating objects, not just WPF ones. Although I was aware of this feature for a long time, I never got around to using it exclusively. Recently in one of my projects I wanted to instantiate a simple Object tree, which has WorflowTypes.Workflow as the root type and a property called Screens that stores objects of type WorflowTypes.Screen. I had to create this structure at my application-startup and I was originally doing it by hand. Instead representing that structure in Xaml appeared to be far more convenient.

Here are the two classes:

Workflow.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Markup;

namespace WorkflowTypes
{
    [ContentProperty("Screens")]
    public class Workflow
    {
        private List<Screen> _screens = new List<Screen>();

        public List<Screen> Screens
        {
            get { return _screens; }
        }

    }
}

Screen.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;

namespace WorkflowTypes
{
    public class Screen
    {
        private string _name;
        private string _parameter;
        private string _transition;
        private Duration _duration;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public string Transition
        {
            get { return _transition; }
            set { _transition = value; }
        }

        public string Parameter
        {
            get { return _parameter; }
            set { _parameter = value; }
        }

        public Duration Duration
        {
            get { return _duration; }
            set { _duration = value; }
        }
    }
}

Note that I specified a class attribute called ContentProperty(“Screens”) for Workflow. This tells the Xaml parser to dump all the child nodes of Workflow into the Screens collection. That makes the Xaml very concise. Without that attribute one would have to use the property-element syntax (<Workflow.Screens>). Here is the Xaml for creating a Workflow instance:

Default.xaml

<loader:Workflow xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                                 xmlns:loader="clr-namespace:WorkflowTypes;assembly=WorkflowTypes">
    <loader:Screen Name="Startup"
                                 Duration="0:0:12"
                                 Transition="GenieTransition"
                                 Parameter="xxx"/>
    <loader:Screen Name="Screen1"
                                 Duration="0:0:12"
                                 Transition="FadeTransition"
                                 Parameter="xxx"/>
    <loader:Screen Name="Screen2"
                                 Duration="0:0:12"
                                 Transition="WipeTransition"
                                 Parameter="xxx"/>
</loader:Workflow>

And in my code-behind I use XamlReader to load this Xaml file as:

In Code-Behind

FileStream stream = new FileStream("Default.xaml", FileMode.Open, FileAccess.Read);
Workflow workflow = XamlReader.Load(stream) as Workflow;

Although the example is pretty simple, you can see the benefits of using Xaml for creating a complex object tree. If you ever have a need to describe all your objects upfront, doing it in Xaml is recommended. It would save you lot of hand-written code.

A side note

If you look at some of the WPF classes like Panel, in addition to the ContentPropertyAttribute, they also implement the IAddChild interface. However that is obsolete and no longer used by XamlReader. Rob Relyea made a post about this sometime back. It is also mentioned in the docs for IAddChild.

Instantiating a custom object-tree in XAML
Pavan Podila
Pavan Podila
February 4th, 2007