Turning XAML into objects using XamlReader

I couldn’t come up with a good title for this post, basically the post is about taking a XAML declared Style and finding the easiest way to turn this into a Style object in code.

I had a problem whereby I ended up with multiple style objects which were exactly the same except for the DataItem they were binding to. This ended up meaning I had lots of duplicate XAML code, apart from one difference. Once I started making the code more dynamic (it was adding columns to the Infragistics XamDataGrid) this XAML became almost useless as I needed to create a style for each dynamically added column and hence really need to generate the Style in code.

If you’ve done anything much with code behind for such things as creating Style objects or replicating XAML code you’ve probably found the code doesn’t always map directly to the XAML, and if you already have XAML that works, why not simply reused it.

Note: The reason the code doesn’t always map is that it includes resources, converters and other XAML magically things that are automatically applied, for example converting colour names to colour values, or field lengths etc.

So let’s simple copy our XAML into a string in code and then programmatically change the DataItem field and then generate our Style object from this.

Here’s an example of the XAML as a string

var styleString = 
   "<Style TargetType=\"{x:Type idp:CellValuePresenter}\">" +
   "<Setter Property=\"Template\">" +
   "<Setter.Value>" +
   "<ControlTemplate>" +
   "<Grid>" +
   "<ListBox ItemsSource=\"{Binding DataItem." + source + "}\">" +
   "<ListBox.ItemTemplate>" +
   "<DataTemplate>" +
   "<TextBlock HorizontalAlignment=\"Stretch\" Text=\"{Binding}\"/>" +
   "</DataTemplate>" +
   "</ListBox.ItemTemplate>" +
   "<ListBox.ItemsPanel>" +
   "<ItemsPanelTemplate>" +
   "<StackPanel Orientation=\"Vertical\"/>" +
   "</ItemsPanelTemplate>" +
   "</ListBox.ItemsPanel>" +
   "</ListBox>" +
   "</Grid>" +
   "</ControlTemplate>" +
   "</Setter.Value>" +
   "</Setter>" +
   "</Style>";

In the above we’d obviously supply the source variable and this will then form part of our XAML style. To turn this into a Style object we need to use the XamlReader.Parse method. Before we can use the XamlReader.Parse method we also need to create the namespaces (context items) that we would expect from our XAML code, in this case we create a ParseContent object and assign our namespaces, then pass this into the XamlReader.Parse method also with the styleString. Our code might look like the following

public Style CreateStyle(string source)
{
   var context = new ParserContext();
   context.XmlnsDictionary.Add
   ("", 
    "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
   context.XmlnsDictionary.Add
   ("x", 
    "http://schemas.microsoft.com/winfx/2006/xaml");

   // other namespaces for XamaDataGrid etc.

   var styleString = 
      "<Style TargetType=\"{x:Type dataPresenter:CellValuePresenter}\">" +
      "<Setter Property=\"Template\">" +
      "<Setter.Value>" +
      "<ControlTemplate>" +
      "<Grid>" +
      "<ListBox ItemsSource=\"{Binding DataItem." + source + "}\">" +
      "<ListBox.ItemTemplate>" +
      "<DataTemplate>" +
      "<TextBlock HorizontalAlignment=\"Stretch\" Text=\"{Binding}\"/>" +
      "</DataTemplate>" +
      "</ListBox.ItemTemplate>" +
      "<ListBox.ItemsPanel>" +
      "<ItemsPanelTemplate>" +
      "<StackPanel Orientation=\"Vertical\"/>" +
      "</ItemsPanelTemplate>" +
      "</ListBox.ItemsPanel>" +
      "</ListBox>" +
      "</Grid>" +
      "</ControlTemplate>" +
      "</Setter.Value>" +
      "</Setter>" +
      "</Style>";

   return (Style)XamlReader.Parse(styleString, context);
}

That’s it – much simpler that create each piece of the Style using C# objects and allows us to first test our XAML out then reused it to generate our objects in code.

Note: If your code relied on namespaces/assemblies which are not already loaded you will have to load them into memory yourself before they can be used in this way.