Code-Beside Files for WF Activity Xaml

Today I’m cheaply recycling yet another perennial forum and mailing list question into a lightweight blog post.

Q. How do I use a custom designer for a XAML activity? On a "normal" code activity I use the [Designer(typeof(MyOwnDesigner))] attribute. How could I apply this attribute on a XAML activity?

My favorite way to do this is use a 'code-beside’ file. Yes, code-beside .xaml.cs aren’t just for WPF.

How to:

  1. You should already have an activity XAML file, say MyActivity.xaml
  2. Right-click the project in VS and ‘Add New Item’.
  3. Choose ‘Class’. Name the file MyActivity.xaml.cs, and hit OK.

Now you should have this:

MyActivity.xaml.cs

In your new file it will make the intent a little clearer if you add one keyword, partial.

namespace WorkflowConsoleApplication1

{

    partial class MyActivity

    {

    }

}

How does this all work anyway? Turning on ‘Show All Files’ will reveal the hidden file in obj\x86\Debug\MyActivity.g.cs

ShowAllFilesButton 

namespace WorkflowConsoleApplication1 {

   

    [System.Runtime.InteropServices.ComVisible(false)]

    public partial class Workflow1 : System.Activities.Activity, System.ComponentModel.ISupportInitialize {

    …

 

This is the simplified diagram of what happens during build:

 

The role of XamlBuildTask

The .g.cs actually contains the XAML runtime loading logic, which provides the definition of your activity class. This file is regenerated by the compiler from your XAML file during build, and is pretty much a fixed format.

Of course the partial class definition we added in our .xamlcs file way up above doesn’t do anything useful yet, but we can add nearly whatever we like, including class attributes or overrides of protected methods on System.Activity, although it is hard to think of really great reasons to do this. So here’s a stupid example which overrides Activity.CacheMetadata to add validation.

namespace WorkflowConsoleApplication1

{

    [Designer(typeof(MyDesigner))]

    partial class MyActivity : Activity

    {

        protected override void CacheMetadata(ActivityMetadata metadata)

        {

            base.CacheMetadata(metadata);

            Activity body = this.Implementation.Invoke();

            if (body as System.Activities.Statements.Sequence == null)

            {

                metadata.AddValidationError(new ValidationError("For some reason MyActivity needs a sequence as root"));

            }

        }

    }

}

 

 

Last tip: for yet other ways to solve the [DesignerAttribute] for XAML activities problem, there are more answers on the original question.