Welcome to MSDN Blogs Sign in | Join | Help

How to use custom ActivityCondition or filter which ActivityConditions are available

If you have your own custom ActivityCondition you are only going to be able to use it with your custom activities, not out of the box activities like While or IfElseBranch.  First start by creating your custom ActivityCondition like the following:

 

[DisplayName("Custom Activity Condition")]

public class CustomActivityCondition : ActivityCondition

{

    public override bool Evaluate(Activity activity, IServiceProvider provider)

    {

        return (this.customCondition.Equals("foo", StringComparison.CurrentCultureIgnoreCase));

    }

 

    private string customCondition = string.Empty;

    public string CustomCondition

    {

        get{ return this.customCondition; }

        set{ this.customCondition = value; }

    }

}

 

Next create a custom TypeConverter that will add your activity condition to the list of available activity conditions for your user to select like below:

 

public class CustomActivityConditionTypeConverter : TypeConverter

{

    private Hashtable conditionDecls = new Hashtable();

 

    public CustomActivityConditionTypeConverter()

    {

        AddTypeToHashTable(typeof(RuleConditionReference));

        AddTypeToHashTable(typeof(CodeCondition));

        AddTypeToHashTable(typeof(CustomActivityCondition));

    }

 

    private void AddTypeToHashTable(Type typeToAdd)

    {

        string key = typeToAdd.FullName;

        object[] attributes = typeToAdd.GetCustomAttributes(typeof(DisplayNameAttribute), false);

        if (attributes != null && attributes.Length > 0 && attributes[0] is DisplayNameAttribute)

            key = ((DisplayNameAttribute)attributes[0]).DisplayName;

        this.conditionDecls.Add(key, typeToAdd);

    }

 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)

    {

        if (sourceType == typeof(string))

            return true;

        return base.CanConvertFrom(context, sourceType);

    }

 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)

    {

        if (value is string)

        {

            if (((string)value).Length == 0 || ((string)value) == "(None)")

                return null;

            else

                return Activator.CreateInstance(this.conditionDecls[value] as Type);

        }

 

        return base.ConvertFrom(context, culture, value);

    }

 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)

    {

        if (destinationType == typeof(string))

            return true;

        else

            return base.CanConvertTo(context, destinationType);

    }

 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)

    {

        if (value == null)

            return "(None)";

 

        object convertedValue = null;

        if (destinationType == typeof(string) && value is ActivityCondition)

        {

            foreach (DictionaryEntry conditionTypeEntry in this.conditionDecls)

            {

                if (value.GetType() == conditionTypeEntry.Value)

                {

                    convertedValue = conditionTypeEntry.Key;

                    break;

                }

            }

        }

 

        if (convertedValue == null)

            convertedValue = base.ConvertTo(context, culture, value, destinationType);

 

        return convertedValue;

    }

 

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)

    {

        ArrayList conditionDeclList = new ArrayList();

 

        conditionDeclList.Add(null);

        foreach (object key in this.conditionDecls.Keys)

        {

            Type declType = this.conditionDecls[key] as Type;

            conditionDeclList.Add(Activator.CreateInstance(declType));

        }

        return new StandardValuesCollection((ActivityCondition[])conditionDeclList.ToArray(typeof(ActivityCondition)));

    }

 

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)

    {

        return true;

    }

 

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)

    {

        return true;

    }

 

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)

    {

        PropertyDescriptorCollection props = new PropertyDescriptorCollection(new PropertyDescriptor[] { });

 

        TypeConverter typeConverter = TypeDescriptor.GetConverter(value.GetType());

        if (typeConverter != null && typeConverter.GetType() != GetType() && typeConverter.GetPropertiesSupported())

        {

            return typeConverter.GetProperties(context, value, attributes);

        }

 

        return props;

    }

 

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)

    {

        return true;

    }   

}   

 

Then to use your custom type converter you just need to add the TypeConverterAttribute to any properties that are ActivityCondition like below:

 

[Browsable(true)]

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

[TypeConverter(typeof(CustomActivityConditionTypeConverter))]

public ActivityCondition MyCustomCondition

{

    get

    {

        return ((ActivityCondition)(base.GetValue(CustomActivityWithCustomActivityCondition.MyCustomConditionProperty)));

    }

    set

    {

        base.SetValue(CustomActivityWithCustomActivityCondition.MyCustomConditionProperty, value);

    }

}

 

To filter the types of ActivityCondition that can be used update the type converter’s constructor to add only the types you want to use like the following which will only display RuleConditionReference and the custom activity condition:

 

public CustomActivityConditionTypeConverter()

{

    AddTypeToHashTable(typeof(RuleConditionReference));

    AddTypeToHashTable(typeof(CustomActivityCondition));

}

 

 

Published Thursday, October 19, 2006 11:44 AM by tomlake
Attachment(s): CustomActivityConditionExample.exe

Comments

Wednesday, September 24, 2008 7:30 AM by Crypt

# re: How to use custom ActivityCondition or filter which ActivityConditions are available

Hi thanks for the tutorial!

But I have one Problem:

I want to bind CustomCondition so I create a depencyproperty:

public static readonly DependencyProperty CustomConditionProperty = DependencyProperty.Register(

   "CustomCondition", typeof(string), typeof(CustomActivityCondition));

   public string CustomCondition

   {

       get { return (string)this.GetValue(CustomConditionProperty); }

       set{ this.SetValue(CustomConditionProperty, value); }

   }

but I get always null

Can you help me?

Mail: sanny_nguyen@online.de

Thank you :)

Tuesday, November 25, 2008 3:28 AM by alexboly

# re: How to use custom ActivityCondition or filter which ActivityConditions are available

"If you have your own custom ActivityCondition you are only going to be able to use it with your custom activities, not out of the box activities like While or IfElseBranch."

This is not completely true. Let's say you have a CustomCondition class that inherits RuleCondition. Then, you:

- create a composed activity that contains IfElseBranch, While etc. activities

- add to the custom activity a property that defines the custom rule

- on setting the value of this property you set the rule on the IfElseBranch to an object of the CustomCondition type

you will see in the designer that the type you use appears and is fully supported! In this case it will be read-only, because you cannot modify activities contained in a composed activity.

The same effect can be created by writing a custom activity that can contain other activities and that attaches to them a DependencyProperty that when set changes the condition to a CustomCondition. You can edit it in the designer with this trick, but you always have to embed IfElse, While etc. activities in this container.

All in all, this limitation is really stupid. Why can't you just write in the designer combo the type of the rule you want to use? (This is displayed when the rule is set to a custom type like above). Why would the designer disallow something that is allowed from the workflow engine? I would like to know who took that decision, so that I can say a few words to them.

Anyway, I'm looking for a solution to avoid this limitation, because I really need custom rule engine support. So any ideas are welcome.

Anonymous comments are disabled
 
Page view tracker