Windows Workflow Foundation - чекор по чекор (custom activity) (3/4)
Workflow концептот на декларативно програмирање ни нуди промена на текот на процесот на лесен, графички начин. Ова ни е овозможено затоа што моделот се состои од малице целини кои добиваат некаков редослед на извршување во зависност од некои влезни параметри. Овие мали целини се наречени Activity-ја. Секое Activity извршува некаква задача во целината. Иако постојат голем број на Activity-ја кои доаѓаат со WF, ние можеме да креираме наши custom activity-ја кои ќе извршуваат некаква задача која нас ни е потребна во нашето workflow.
Зошто custom activity-ја?
Custom Activity-јата ни овозможуваат да развиваме мали компоненти, кои можеме да ги тестираме како самостојни единки а потоа да ги употребуваме во повеќе проекти. Кога ќе го развиеме, можеме да ги додадеме во нашиот toolbox и да ги додаваме во workflow-ата со едноставен drag-drop.
Во нашиот претходен проект употребувавме две Code Activity-ја, каде во првото собиравме а во второто одземавме. Доколку имаме некоке сложено workflow каде се одвиваат десетина собирања и десетина доземања, имплементацијата на ваково Custom Activity за собирање и одземање би ни ја олеснало работата. Токму тоа и ќе го направиме во овој случај.
Прво што треба да направиме е да додадеме едно Activity во нашиот проект. Десен click на проектот > Add > Activity
Потоа му задаваме име, во случајот SumSubCustomActivity.cs
Проектот автоматски ни додава SequenceActivity тип, каде можеме да додаваме повеќе други Activity-ја внатре во нашето Custom Activity (CA). Но за примеров ние ќе искористиме друг тип на CA, од најдиско ниво, односно наследено дирекно од Activity класата. За да го направиме тоа, во properties на креираното CA го мениваме пропертито Base Class и избираме Type > System.Workflow.ComponentModel > и во десниот дел Activity
Крајниот резултат на изгледот на дизајнерот треба да биде следен:
Сега се префрламе на кодот каде ќе ја имплементираме нашата логика. Треба да креираме три property-ја, каде првата е типот на операцијата (собирање или одземање), а останатите две да бидат броевите кои ќе ги собираме или одземаме. За определување на типот на операцијата користиме Enum.
public enum OperationType
{
Sum = 1,
Sub = 2
}
public static DependencyProperty OperationProperty = System.Workflow.ComponentModel.DependencyProperty.Register("Operation", typeof(OperationType), typeof(SumSubCustomActivity));
/// <summary>
/// Identifies the operation
/// </summary>
[Description("Identifies the operation")]
[Category("Custom Activity Example")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public OperationType Operation
{
get
{
return ((OperationType)(base.GetValue(SumSubCustomActivity.OperationProperty)));
}
set
{
base.SetValue(SumSubCustomActivity.OperationProperty, value);
}
}
public static DependencyProperty Num1Property = System.Workflow.ComponentModel.DependencyProperty.Register("Num1", typeof(Int32), typeof(SumSubCustomActivity));
[Description("Number 1")]
[Category("Custom Activity Example")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Int32 Num1
{
get
{
return ((Int32)(base.GetValue(SumSubCustomActivity.Num1Property)));
}
set
{
base.SetValue(SumSubCustomActivity.Num1Property, value);
}
}
public static DependencyProperty Num2Property = System.Workflow.ComponentModel.DependencyProperty.Register("Num2", typeof(Int32), typeof(SumSubCustomActivity));
[Description("Number 2")]
[Category("Custom Activity Example")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Int32 Num2
{
get
{
return ((Int32)(base.GetValue(SumSubCustomActivity.Num2Property)));
}
set
{
base.SetValue(SumSubCustomActivity.Num2Property, value);
}
}
Во кодот се забележува дека се употребува т.н. Dependency Property (DP). Разликата на овој тип на Property е тоа што користи зачувување на вредноста во рамки на workflow instance-ата за разлика од основните property-ја кои се во меморија во рамки на класата. Исто така овој тип на property-ја се видливи во runtime така да вредноста на едно DP може да биде излез од неговата работа а таа вредност потоа да ја превземи некое друго CA и да ја искористи за неговата задача.
На крајот креираме override на Execute методот наследен од Activivty base класата, кој се извршува при извршување на самото CA.
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
switch (Operation)
{
case OperationType.Sum:
int sum = Num1 + Num2;
Console.WriteLine("Sum is: " + sum.ToString());
break;
case OperationType.Sub:
int sub = Num1 - Num2;
Console.WriteLine("Sub is: " + sub.ToString());
break;
}
return base.Execute(executionContext);
}
Сега може да го build-аме проектот и да го додеме нашето CA во workflow-то. Кога ке го отвориме дизајнерот на workflow ќе замележиме дека во горниот дел на toolbox-от има група на компоненти кои се дефинирани во рамки на овој проект. Во таа група се наоѓа и нашето CA.
Како што споменав претходно го додаваме со едноставен Drag-Drop. Претходно ќе ги избришеме Code Activity-јата од двете гранки.
Забележуваме дека protpery-јата кои ги дефиниравме во нашето CA се достапни во runtime и можеме да им доделиме вредност (да ги bind-уваме) на некои од workflow property-ја. За да го постигнеме тоа ги бришеме досегашните Num1 и Num2 и ги креираме со Dependency Property-ја:
public static DependencyProperty WFNum1Property = System.Workflow.ComponentModel.DependencyProperty.Register("WFNum1", typeof(Int32), typeof(Workflow1));
[Description("Number 1")]
[Category("WF Properties")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Int32 WFNum1
{
get
{
return ((Int32)(base.GetValue(Workflow1.WFNum1Property)));
}
set
{
base.SetValue(Workflow1.WFNum1Property, value);
}
}
public static DependencyProperty WFNum2Property = System.Workflow.ComponentModel.DependencyProperty.Register("WFNum2", typeof(Int32), typeof(Workflow1));
[Description("Number 2")]
[Category("WF Properties")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Int32 WFNum2
{
get
{
return ((Int32)(base.GetValue(Workflow1.WFNum2Property)));
}
set
{
base.SetValue(Workflow1.WFNum2Property, value);
}
}
Потоа вредностите на CA соодветно ги превземаме од WF. Го селектираме CA во левата гранка и Num1 property-то го bind-уваме на WFNum1 property-то од WF-то.
Соодветно и за вториот број Num2 со WFNum2 и на крајот за Operation од листата избираме Sum. Постапката ја повторуваме и за CA во десната гранка со што операцијата сега е Sub. Го build-аме проектот да видиме дали се е во ред.
На ред пе промена во конзолната апликација, затоа што ги променивме иминјата на пропертијата во workflow-то. сега се викаат WFNum1 и WFNum2.
wfArguments.Add("WFNum1", 4);
wfArguments.Add("WFNum2", 3);
Ја старуваме апликацијата и гледаме дека го добиваме истиот резултат и за операцијата Sum и за операцијата Sub.