Types, Metatypes and Bears, Oh my!

***** UPDATE: Please see this post for how these features and functionality work in Beta2 *****

This post comes about after a little conversation on the forums where I was talking about using the xaml stack save and load objects.

Here’s what I said:

Bob (it’s a little late in Seattle, so I don’t have a code editor handy, so there may be some minor errors below), If you want to serialize any object graph to xaml, simply look at the XamlServices.Save() api that’s in System.Xaml. I’m sure there are a few SDK samples around that as well. It takes in a file name to output to, a text writer or a stream, so you get to pick your poison for destination. Similarly, if you want to get an object graph deserialized from Xaml, you can just use XamlServices.Load() again, with overloads for files, streams, text, xml, and xaml readers. To see this API, just do something like

If you want to read, basically do the reverse. Save and Load are convinient helper functions to operate on the whole of the doc, there Xaml stack surfaces much more programmability and has a nice node stream style API that lets you plug in while nodes are being read and written. Now, if you want to deserialize a Xaml file that contains an x:Class directive, you are going to need to do a bit more work (and it depends what you want to serialize to or from). I’ll try to blog about that in the next week or so.

Now, I want to take a little bit of time to explain the last part.

A convenient way to think about XAML is a way to write down objects, really, instances of objects. That said I am not limited to writing down just instances, I can actually write down type definitions as well. I do this using the x:Class attribute.

Consider the following XAML snippet

<Activity x:Class=”foo” …

This is roughly equivalent to the following C#

publicclass foo : Activity
{
…

Now, “normally” what happens with XAML like this in .xaml files is that it is used in a VS project and it is set up so that there is a build task who has the job of generating a type from that XAML so that you can use that type subsequently in your application. This works basically the same way for WPF as well as WF.

However, if you think about trying simply deserialize this, it’s a little confusing what this will actually deserialize to. This is a type definition, so if you simply try to pass it to XamlServices.Load(), you will encounter an exception:

Error System.Xaml.XamlObjectWriterException: No matching constructor found on type System.Activities.Activity. You can use the Arguments or FactoryMethod direct ives to construct this type. —> System.MissingMethodException: No default constructor found for type System.Activities.Activity. You can use the Arguments or FactoryMethod directives to construct this type. at System.Xaml.Runtime.ClrObjectRuntime.DefaultCtorXamlActivator.EnsureConstructorDelegate(XamlType xamlType) at System.Xaml.Runtime.ClrObjectRuntime.DefaultCtorXamlActivator.CreateInstance(XamlType xamlType) at System.Xaml.Runtime.ClrObjectRuntime.CreateInstanceWithCtor(XamlType xamlType, Object[] args) at System.Xaml.Runtime.ClrObjectRuntime.CreateInstance(XamlType xamlType, Object[] args) — End of inner exception stack trace —

So, if we want to deserialize that, we need to ask the question first: “Why do we want to deserialize it?”

Deserialize to Execute

If we want to simply use the activity we’ve created and have it execute, we have a special type, DynamicActivity. DynamicActivity lets you execute the activity, and rather than creating a type for it, will allow you to pass in the arguments in the typical Dictionary<string,object> way that we are used to.

Imagine a xaml file, just sitting on disk somewhere that looks like this (a workflow that concats two strings):

Deserialize to “Design”

At design time, we have an even more interesting problem. Our designer is an instance editor, and, as such, it must always edit an instance of “something”. In our case, we actually do some work in our design time xaml reader and writer to deserialize into a metatype, an instance of a type whose sole purpose in life is to describe the activity. In Beta1, this is called ActivitySchemaType. ActivitySchemaType simply models the type structure of an activity, complete with properties, etc If you want to construct an instance of an ActivitySchemaType in code, you can, and then you could use the DesignTimeXamlWriter in order to properly serialize out to an Activity x:class xaml file. The following code works on an ActivitySchemaType in memory and then serializes it: