An Activity Designer for InvokeAction<T>

[Update! There are some bugs with the attached code, see the sequel post for discussion of bug fixes.]

My workmate Ramraj mentioned that a long way back (during earlier milestones of WF 4.0) something was invented for XAML called a property reference, which was a feature that in the workflow designer would enable creating custom XAML activities 'with holes’ for plugging in actions. More specifically, it enables authoring an InvokeAction<T> activity designer, so that an InvokeAction<T> activity in your workflow can invoke a certain ActivityAction<T> property which was set on your workflow.

This feature is kind of strange because it is hard to imagine how it could work using real CLR properties. Scenario:

- You have CLR property 'Action' on an InvokeAction activity.
- You want it to be exactly the same value as CLR property 'Action' on your custom Xaml Activity (which wraps the InvokeAction activity)
- There is no value of Action yet - so you can't just literally set the two properties to be the same value.
- You need one CLR to 'refer' to another one, as if overriding its getter to do

Action { get { return otherGuy.Action } }

But this seems impossible, because of course with normal CLR objects you can't selectively override properties in this way. Where a little magic is able to enter, and save the day, is the fact that we aren't restricted to dealing with actual CLR objects. The properties only need to be set to equal the same value when the workflow XAML definition for our custom activity is invoked - which, with a few ifs and buts, might be when the needed property value is already known (hint: there are some ways this can fall down).

So back to the original story - I heard this construct existed in the past as a prototype, but more recently (thanks to forum post here) I found out the functionality is actually alive and well in the 4.0 framework, and is even highlighted by one of the XAML samples!

It looks like this:

<Activity mc:Ignorable="sap" x:Class="Microsoft.Samples.Activities.ShowDateTimeAsAction" [namespaces omitted]>
    <x:Property Name="CustomAction" Type="ActivityAction(x:String)" />

  <InvokeAction x:TypeArguments="x:String" Argument="[str]" sap:VirtualizedContainerService.HintSize="200,82">
      <PropertyReference x:TypeArguments="ActivityAction(x:String)" PropertyName="CustomAction" />


The PropertyReference is tying the Action property (of type InvokeAction<string>), to the CustomAction property of the ShowDateTimeAsAction class.

So… the framework has support so that you can do all this through XAML. Which is cool. But nothing in XAML is cool enough without a designer experience...

If you want to dig deeper, there’s also a couple mysterious aspects to the above XAML.

-What’s this <PropertyReference> class?
-Why does the value of Action still appear to be null, after you deserialize it using WorkflowDesigner.Load()?
-Even though Action appears as null, the <PropertyReference> data survives loading, editing, and saving in the designer, and getting saved back to XAML?

So definitely something unusual is going on. It works by certain classes which do some custom XAML serialization/deserialization: ActivityPropertyReference, ActivityBuilder, and System.Xaml.AttachablePropertyServices.

Now as I really just want to know how we could use this in designer, the important point for me is that we can find the PropertyReference which has been loaded from XAML, and do something with it.

What we get when we load the above sample XAML (which had some bits cut out) is an object tree something like

                +—ActivityAction(with an attached property)

where the attached property is


We get/set the attached property using these APIs:

ActivityBuilder.GetPropertyReference(object target)
ActivityBuilder.SetPropertyReference(object target, ActivityPropertyReference value)

Now that we have this cool information, we should be able to make a designer for InvokeAction<T>, right? Right. Really. This is what it looks like in action:


Download the attached code to play with it yourself. (P.S. I only tested it with InvokeAction<string> so far, let me know in the comments if you have issues....)

Comments (5)

  1. Nick C says:

    Hi Tim

    Really good!  However, if I change the PropertyReference to a VariableReference, I get an error:

    <?xml version="1.0" encoding="utf-8"?>

    <!– Copyright (c) Microsoft Corporation.  All rights reserved. –>

    <Activity x:Class="Microsoft.Samples.Activities.ShowDateTimeAsAction"







       <x:Property Name="CustomAction" Type="ActivityAction(s:String)"/>




         <Variable Name="str" x:TypeArguments="s:String" />

    <Variable x:TypeArguments="swm:ActivityAction(s:String)" Name="action"  x:Name="__action"/>


       <sample:GetDateTime Date="[str]" />

       <InvokeAction x:TypeArguments="s:String" Argument="[str]">


    <!– <PropertyReference x:TypeArguments="swm:ActivityAction(s:String)"

    PropertyName="CustomAction" /> –>

    <VariableReference x:TypeArguments="swm:ActivityAction(s:String)" Variable="{x:Reference __action}">






    Gives: Error 1 Unexpected object of type ‘System.Activities.Expressions.VariableReference(ActivityAction(String))’. Member ‘System.Activities.Statements.InvokeAction(String).Action’ expects item of type ‘System.Activities.ActivityAction(String)’.

    D:CodeWF_WCF_SamplesWFBasicCustomActivitiesCode-BodiedActivityActionCSSimpleActivityShowDateTimeAsAction.xaml 22 5

    Where am I going wrong?  The PropertyReference and VariableReference both inherit from System.Activities.CodeActivity<Location<TResult>>, so it should be a straight swap.



  2. tilovell09 says:

    Hi Nick,

    I probably wasn’t clear enough about this in the article. This ActivityAction designer relies on a special XAML feature for attached properties.

    When you look at the XAML it looks like <PropertyReference> is just another XAML tag. In which case you can also logically think that it is an instance of the PropertyReference class in System.Activities.Expressions. However, although the explanation gets rather technical that is not actually the case.

    The PropertyReference<> you are looking at is System.Activities.Expressions.PropertyReference.

    But magically, the <PropertyReference> XAML tag is actually being converted into an *ActivityPropertyReference* object. The magic is from System.Xaml.AttachablePropertyServices and custom XAML handling in DynamicActivityXamlReader.

    So how can <PropertyReference> deserialize as <ActivityPropertyReference>?

    In fact XAML lets the workflow runtime (or you if you want) intercept any XML nodes and attributes, and convert them to attached property references, or indeed interpret them however you like (transform them to refer to another type etc).

    Back to your question, of how you can use a VariableReference, the question is just a little bit off base. The reason is that on one hand, the activity expects an ActivityAction<String>, which is like a delegate function to run with a string input. On the other hand, you are passing a VariableReference – which is actually an Activity<ActivityAction<String>>. So I think something or other needs to change in your design…

    (PropertyReference. on the other hand. is really giving back the type of the referenced property, which is ActivityAction<String>.)

  3. Nick C says:

    Hi Tim,

    Thanks for your response – might need to read it a few more times before I get my head around it, but I think I get what you are saying.

    Having a look at the design seems like good advice – here is what I am trying to do…

    I want to build a WCF Workflow service that takes a file name as a parameter.  An activity will then use the file name to load a bit of xaml and place it into an ActivityAction variable (I can do this bit without any problems).  I then want to execute the xaml by passing the ActityAction to InvokeAction.  In other words, I want to use the InvokeAction to dynamically change the workflow that is being run.

    Does this make sense?  Am I breaking a fundamental rule of WF4 by altering a workflow that is already running?

    Thanks for your help


  4. tilovell09 says:

    >Does this make sense?  Am I breaking a fundamental rule of WF4 by altering a workflow that is already running?

    My current belief is that yes, it is against the rules. When you invoke a workflow WF4 has a phased system:

    1) Validate the workflow by calling CacheMetadata recursively. This also records the activity parent child relationships. Your workflow is still not executing at this point.

    2) Execute the workflow. If. while executing your workflow definition doesn’t match the definition found by CacheMetadata, you will get runtime exceptions complaining that you changed the workflow definition.

    I know the above applies to regular Activities, and I think the rule applies even to ActivityDelegates.

    For some scenarios you might be able to work around the issue by invoking C# delegates, or invoking a whole new worklfow.

  5. tilovell09 says:

    Added a sequel post.


Skip to main content