One powerful feature of a workflow is that a workflow can be changed at runtime. Like other powerful features this is something that should be done with care but it can be a real life saver at times.
One of the things that you can change are Declarative Rule Conditions. However as these rules are really CodeDom objects it can be a bit tricky to find the right property to change. However once you know a little tick life is much easier.
The trick is in the .rules file created when you add a Declarative Rule Condition to the workflow and is best demonstrated using a small example. Take the following workflow:
The IfElseActivity has a Declarative Rule Condition which looks like this:
So I consider every amount larger that 100 large. Hmm not much, lets change that to 1000 instead of 100 [:)]
The first step is we need to change the workflow instance so we need a WorkflowChanges object passing in the workflow root as the activity. No big deal but what now. Well lets open the Workflow1.Rules file and take a look at what is inside.
<RuleDefinitions xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"> <RuleDefinitions.Conditions> <RuleExpressionCondition Name="LargeAmountRule"> <RuleExpressionCondition.Expression> <ns0:CodeBinaryOperatorExpression Operator="GreaterThan" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=126.96.36.199, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns0:CodeBinaryOperatorExpression.Left> <ns0:CodePropertyReferenceExpression PropertyName="Amount"> <ns0:CodePropertyReferenceExpression.TargetObject> <ns0:CodeThisReferenceExpression /> </ns0:CodePropertyReferenceExpression.TargetObject> </ns0:CodePropertyReferenceExpression> </ns0:CodeBinaryOperatorExpression.Left> <ns0:CodeBinaryOperatorExpression.Right> <ns0:CodePrimitiveExpression> <ns0:CodePrimitiveExpression.Value> <ns1:Int32 xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=188.8.131.52, Culture=neutral, PublicKeyToken=b77a5c561934e089">100</ns1:Int32> </ns0:CodePrimitiveExpression.Value> </ns0:CodePrimitiveExpression> </ns0:CodeBinaryOperatorExpression.Right> </ns0:CodeBinaryOperatorExpression> </RuleExpressionCondition.Expression> </RuleExpressionCondition> </RuleDefinitions.Conditions> </RuleDefinitions>
It turns out that the XML is a very literal representation of the objects that make up our rule and what we need to change. So we need to start with a RuleDefinitions.
RuleDefinitions rules = (RuleDefinitions)changes.TransientWorkflow.GetValue(RuleDefinitions.RuleDefinitionsProperty);
So getting our hand on it is easy, just use the GetValue function passing in the RuleDefinitionsProperty dependency property.
Once we have this things are even easier as it is just following the XML [:)]. It shows the RuleDefinitions object has a Conditions property and our rule is in there with a name LargeAmountRule and is of type RuleExpressionCondition. This rule in turn contains a left and right part with the right part pointing at the value of 100 we want to change. Again this value is of a type CodePrimitiveExpression, another easy cast. The code below is the complete code required to change the value from 100 to1000.
WorkflowChanges changes = new WorkflowChanges(this); RuleDefinitions rules = (RuleDefinitions)changes.TransientWorkflow.GetValue(RuleDefinitions.RuleDefinitionsProperty); RuleExpressionCondition rule = (RuleExpressionCondition)rules.Conditions .First(rc => rc.Name == "LargeAmountRule"); CodeBinaryOperatorExpression expression = (CodeBinaryOperatorExpression)rule.Expression; CodePrimitiveExpression primitive = (CodePrimitiveExpression)expression.Right; primitive.Value = 1000; ApplyWorkflowChanges(changes);
Easy once you know where to look [:)]