Friday, 9 July 2010

XAML for non-UI data

I hadn't considered using XAML to describe non-UI data or using the XamlReader to load/parse a XML data file. This post is a simple step-by-step guide to defining a XAML model and the associated C# classes to load our StateMachine Maps.

Starting with the bare minimum XAML and data class:
<MapLoader
xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</MapLoader>

[Serializable]
public class MapLoader
{
public static MapLoader Load(string location)
{
return (MapLoader)XamlReader.Load(new XmlTextReader(location));
}
}


Adding a collection of States:

<MapLoader
xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<MapLoader.States>
<State Name="Start">
</State>
</MapLoader.States>

</MapLoader>

[Serializable]
public class MapLoader
{
public StateList States { get; set; }

public MapLoader()
{
States = new StateList();
}


public static MapLoader Load(string location)
{
return (MapLoader)XamlReader.Load(new XmlTextReader(location));
}
}

[Serializable]
public class StateList : List<State> { }

[Serializable]
public class State
{
public string Name { get; set; }
}



Each State has a collection of Events:


<MapLoader
xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<MapLoader.States>
<State Name="Start">

<State.Events>
<Event Name="OnGoToFirstPage" />
</State.Events>

</State>
</MapLoader.States>
</MapLoader>

[Serializable]
public class MapLoader
{
public StateList States { get; set; }

public MapLoader()
{
States = new StateList();
}
public static MapLoader Load(string location)
{
return (MapLoader)XamlReader.Load(new XmlTextReader(location));
}
}

[Serializable]
public class StateList : List<State> { }

[Serializable]
public class State
{
public string Name { get; set; }

public State()
{
Events = new EventList();
}

}

[Serializable]
public class EventList : List<Event> { }
[Serializable]
public class Event
{
public string Name { get; set; }
}



By decorating the MapLoader and State classes with the [ContentProperty] attribute we avoid the need to explictly reference the collection classes:

<MapLoader
xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<State Name="Start">
<Event Name="OnGoToFirstPage"/>
</State>
<State Name="FirstPage">
<Event Name="OnGoToLastPage"/>
<Event Name="OnGoToMiddlePage"/>
</State>

</MapLoader>

[Serializable]
[ContentProperty("States")]

public class MapLoader
{
public StateList States { get; set; }

public MapLoader()
{
States = new StateList();
}
public static MapLoader Load(string location)
{
return (MapLoader)XamlReader.Load(new XmlTextReader(location));
}
}

[Serializable]
[ContentProperty("Events")]

public class State
{
public string Name { get; set; }

public State()
{
Events = new EventList();
}
}


Final version with all the attributes defined for States and Events:

<MapLoader
xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<State Name="Start">
<Event
Name="OnGoToFirstPage"
GotoState="FirstPage"
RunAction="DisplayFirstPage"
LayoutX="440"
LayoutY="120" />
</State>
<State
Name="FirstPage"
LayoutX="320"
LayoutY="200">
<Event
Name="OnGoToLastPage"
GotoState="LastPage"
RunAction="DisplayLastPage"
LayoutX="660"
LayoutY="260" />
<Event
Name="OnGoToMiddlePage"
GotoState="MiddlePage"
RunAction="DisplayMiddlePage"
LayoutX="440"
LayoutY="300" />
</State>
</MapLoader>

[Serializable]
[ContentProperty("States")]
public class MapLoader
{
public StateList States { get; set; }

public MapLoader()
{
States = new StateList();
}
public static MapLoader Load(string location)
{
return (MapLoader)XamlReader.Load(new XmlTextReader(location));
}
}

[Serializable]
[ContentProperty("Events")]
public class State
{
public string Name { get; set; }
public int LayoutX { get; set; }
public int LayoutY { get; set; }
public EventList Events { get; set; }

public State()
{
Events = new EventList();
}
}

[Serializable]
public class Event
{
public string Name { get; set; }
public string GotoState { get; set; }
public string RunAction { get; set; }
public int LayoutX { get; set; }
public int LayoutY { get; set; }

}

[Serializable]
public class StateList : List<State> { }

[Serializable]
public class EventList : List<Event> { }

No comments: