ExpressionTextBox 101

The ExpressionTextBox is the basic building block for editing expressions in custom activity designers. If you’re writing a custom activity designer that uses expressions, you’ll use this control. This post is meant to provide an overview for custom activity designer developers. I’m just going to annotate a small amount of the SDK sample and walk through it step by gory step. For those with short attention spans, skip this post and just take a look at the ExpressionTextBox SDK sample instead.   

Start with a new activity designer, and make sure you have the following namespaces available:

 <sap:ActivityDesigner x:Class="Microsoft.Samples.ExpressionTextBoxSample.MultiAssignDesigner"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
    xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation" 
    xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
>

Expressions are bound to arguments using the ArgumentToExpressionConverter*, which is in the System.Activities.Presentation.Converters namespace.  Add this converter to your resource dictionary, like so:

     <sap:ActivityDesigner.Resources>
        <ResourceDictionary>
            <sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
        </ResourceDictionary>
    </sap:ActivityDesigner.Resources>

Now you can go on to adding your ExpressionTextBox. First, you need to figure out which type of expression you are editing. You can edit two types of expressions inside of an ExpressionTextBox, location expressions (or L-value expressions) and value expressions. Value expressions do what they say on the box. They are expressions that evaluate to a value, and you can place them on the right hand side of an assignment statement. InArguments correspond to value expressions, and are serialized as VisualBasicValue expressions (shortened to [] when serialized from the designer). Now, let’s pretend we have an activity with an InArgument named FooValue of type String. Here is a simplified ExpressionTextBox that binds to that argument:

 <sapv:ExpressionTextBox 
    Expression="{Binding Path=ModelItem.FooValue, 
                         Mode=TwoWay, 
                         Converter={StaticResource ArgumentToExpressionConverter}, 
                         ConverterParameter=In }"
    ExpressionType="s:String"
    OwnerActivity="{Binding Path=ModelItem}"
   />

Obviously, you’d set other properties in the real world, but the two that you absolutely must set are Expression and OwnerActivity. It is important to set ExpressionType as well, otherwise you will see some wonky behavior. Take a look at that expression binding – Path is to the argument to which you are binding, mode is almost always TwoWay, and then we pass the In parameter to the ArgumentToExpressionConverter to tell it that we are binding to an InArgument.

Conversely, location expressions correspond to OutArguments and are serialized as VisualBasicReference expressions (shortened to [] when serialized from the designer). You can put a location expression on the left hand side of an assignment statement. Now, let’s pretend we have an activity with an OutArgument named FooReference of type String. Here is a simplified ExpressionTextBox to bind to that argument.

 <sapv:ExpressionTextBox 
      Expression="{Binding Path=ModelItem.FooReference, 
                           Mode=TwoWay, 
                           Converter={StaticResource ArgumentToExpressionConverter}, 
                           ConverterParameter=Out }"
      OwnerActivity="{Binding Path=ModelItem}"
      ExpressionType="s:String" 
      UseLocationExpression="True" 
/>

There are two differences from the previous example. Since we are binding to a L-value expression, the UseLocationExpression property is True. Because we are binding to an OutArgument, the ConverterParameter is Out.

Not shown today: binding ExpressionTextBoxes to CLR properties and binding to untyped arguments. Those will be subjects of another post.

*Aside – this is the only convenient converter for binding basic UI elements to arguments (WorkflowItem[s]Presenter excepted). In this release, you have to write your own converter to bind say a check box to a boolean argument.