Friday, 14 October 2011

Constraining Dropped Activities

In my last post I described making modifications to the standard FlowDecision activity to make it more usable, and mentioned there were a couple of modifications I needed to make to the code to make it more usable.

One is constraining the types of activity that can be dropped into the FlowDecision. Where I left off on that last post was something that looked as follows…

image

The problem here is at present I can drop anything into the FlowDecision – instead I need to constrain this to only activities that return a boolean result, i.e. something derived from Activity<Boolean>. I’m using the WorkflowItemPresenter in my designer and there’s a property on there named AllowedItemType which does just the job – however what I need to do is be able to pass a generic type into this type. A quick search around the web had something close, so here’s what I now have in the XAML…

    <sap:ActivityDesigner.Resources>
<
local:GenericType x:Key="mustReturnBool" BaseType="{x:Type sa:Activity`1}"
TypeParam="{x:Type sys:Boolean
}" />
</
sap:ActivityDesigner.Resources
>

<
sap:WorkflowItemPresenter Item="{Binding ModelItem.Condition}"
HintText="Drop a condition here" AllowedItemType="{StaticResource mustReturnBool
}"/>

So here I have a markup extension (local:GenericType) and have referenced this in the workflow item presenter. The markup extension defines the class we’re deriving from which is a generic type taking one argument so is defined as Activity`1 (if this took 3 arguments you would define this as Activity`3). I’ve then defined the type parameter as an instance of Boolean, and so at runtime this will create a type which is Activity<Boolean>.


Note: If you happen to cut & paste the line from the XAML that includes sa:Activity`1 this will (most annoyingly) be pasted back in as sa:Activity’1 – i.e. the grave character has been replaced with a single quote. So, beware!


The markup extension is shown below…

/// <summary>
///
A markup extension allowing generic types to be used in XAML
/// </summary>
public class GenericType :
MarkupExtension
{
/// <summary>
///
Defines the base type to derive from
/// </summary>
public Type BaseType { get; set; }

/// <summary>
///
Defines the collection of type parameters
/// </summary>
public Type[] TypeParams { get; set; }

/// <summary>
///
Defines the singular type parameter
/// </summary>
public Type TypeParam { get; set; }

/// <summary>
///
Default constructor
/// </summary>
public GenericType() { }

/// <summary>
///
Return the generic type constructed from the base Type and Type parameters
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
Type retVal = null;

if (null != TypeParam)
retVal = BaseType.MakeGenericType(TypeParam);
else
retVal = BaseType.MakeGenericType(TypeParams);
return retVal;
}
}


With this in place I can try dragging any old activity onto the FlowDecision and now it won’t permit me to drop anything other than activities that derive from the correct type.


The Code


I’ve updated the code from the last article to include this new capability. Click here to download a .zip.

No comments: