创建自定义复合活动
创建自定义复合活动时,如果您为自定义复合活动设计和创建默认逻辑,则有以下几种选择。
为自定义复合活动添加设计时支持
如果您的活动派生自 CompositeActivity 并希望为其提供设计时支持,则必须将 DesignerAttribute 设置为 CompositeActivityDesigner 的派生,如 ParallelActivityDesigner 或 SequentialActivityDesigner。 当然,您也可以通过直接从 CompositeActivityDesigner 派生来创建自己的复合活动设计器。
例如,如果要创建镜像 ParallelActivity 活动的设计时体验的自定义复合活动,则必须将以下代码添加到您的自定义活动定义中:
<Designer(GetType(ParallelActivityDesigner), GetType(IDesigner))> _
Public Class CustomCompositeActivity
Inherits CompositeActivity
' Define custom activity here.
End Class
[Designer(typeof(ParallelActivityDesigner), typeof(IDesigner))]
public class CustomCompositeActivity : CompositeActivity
{
// Define custom activity here.
}
还可以使用 SequentialActivityDesigner 来创建镜像 SequenceActivity 活动的设计时体验的自定义活动,但更简单的方法是从 SequenceActivity 自身派生您的自定义活动。 同样,通过将此活动作为您的自定义活动的基类,可以为您提供以顺序方式计划活动的执行的默认逻辑。
相反,如果希望隐藏您的自定义复合活动的内部结构,如从 SequenceActivity 派生的内部结构,则应将 DesignerAttribute 设置为 ActivityDesigner,因为此类型不具备对复合活动的运行时支持。
为自定义复合活动添加子活动
可以选择为您的自定义活动添加子活动的方式。 可以使用两种方法为您的自定义复合活动添加子活动:
从 SequenceActivity 派生自定义活动。
从 CompositeActivity 派生自定义活动。
CompositeActivity 活动不包含用于处理子活动的默认逻辑。 如果希望创建自定义复合活动,还必须重写 Execute 来处理您的子活动和 Cancel 的执行,以取消您的子活动和关闭自定义活动。
下面的示例演示如何将 CodeActivity 活动添加到行为与 ParallelActivity 活动类似的自定义复合活动。 还必须从 IActivityEventListener 继承,以便在子活动上引发 Closed 和 Executing 事件时得到通知。
<Designer(GetType(ParallelActivityDesigner), GetType(IDesigner))> _
Public Class CustomCompActivity
Inherits CompositeActivity
Implements IActivityEventListener(Of ActivityExecutionStatusChangedEventArgs)
' Declare variables.
Private ca1 As CodeActivity
Private ca2 As CodeActivity
Private ca3 As CodeActivity
Private ca4 As CodeActivity
Private index As Integer
Public Sub New()
InitializeComponent()
End Sub
' Initialize your child activities and add them to your custom
' composite activity.
Private Sub InitializeComponent()
Me.CanModifyActivities = True
Me.ca1 = New CodeActivity("CodeActivity1")
Me.ca2 = New CodeActivity("CodeActivity2")
Me.ca3 = New CodeActivity("CodeActivity3")
Me.ca4 = New CodeActivity("CodeActivity4")
AddHandler ca.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca2.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca4.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca4.ExecuteCode, AddressOf ca_ExecuteCode
Me.Activities.Add(ca1)
Me.Activities.Add(ca2)
Me.Activities.Add(ca3)
Me.Activities.Add(ca4)
' Cache index value of last child activity in the collection.
index = Me.Activities.Count - 1
Me.CanModifyActivities = False
End Sub
Protected Overrides Function Execute(ByVal ExecutionContext As ActivityExecutionContext) As ActivityExecutionStatus
If (ExecutionContext Is Nothing) Then
Throw New ArgumentNullException("ExecutionContext")
End If
' If there are no child activities initialized, then close
' the parent activity.
If (Me.EnabledActivities.Count = 0) Then
Return ActivityExecutionStatus.Closed
End If
' Cycle through all of the enabled child activities in your
' activity, register for their Closed and Executing events,
' and then run the child activity.
Dim i As Integer
For i = 0 To Me.EnabledActivities.Count - 1 Step +1
Dim ChildActivity As Activity = Me.EnabledActivities(i)
ChildActivity.RegisterForStatusChange(Activity.ClosedEvent, Me)
ChildActivity.RegisterForStatusChange(Activity.ExecutingEvent, Me)
ExecutionContext.ExecuteActivity(ChildActivity)
Next
Return ActivityExecutionStatus.Executing
End Function
' This event handler is used for the ExecuteCode event that
' each CodeActivity activity will raise during its execution.
Private Sub ca_ExecuteCode(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("In event handler for {0}.ExecuteCode event...", CType(sender, Activity).Name)
End Sub
' Implement the IActivityEventListener.OnEvent method to
' display the current activity state and close your
' parent custom activity when all of the child activities are
' are either in the Initialized or Closed state. Otherwise, keep
' the parent activity running.
Sub OnEvent(ByVal Sender As Object, ByVal E As ActivityExecutionStatusChangedEventArgs) Implements IActivityEventListener(Of System.Workflow.ComponentModel.ActivityExecutionStatusChangedEventArgs).OnEvent
If (Sender Is Nothing) Then
Throw New ArgumentNullException("Sender")
End If
If (E Is Nothing) Then
Throw New ArgumentNullException("E")
End If
Dim Context As ActivityExecutionContext = CType(Sender, ActivityExecutionContext)
If (Context Is Nothing) Then
Throw New ArgumentException("The sender must be an ActivityExecutionContext object", "Sender")
End If
Dim CustActivity As CustomCompActivity = CType(Context.Activity, CustomCompActivity)
' Display the current state of the child activity.
Console.WriteLine("{0} is in the {1} state.", E.Activity.Name, E.ExecutionStatus)
' As a good coding practice, unregister for the Closed event if
' the child activity is in the closed state.
If (E.Activity.ExecutionStatus = ActivityExecutionStatus.Closed) Then
E.Activity.UnregisterForStatusChange(Activity.ClosedEvent, Me)
End If
' Check whether the activity passed into the payload of the
' ActivityExecutionStatusChangedEventArgs object is the last
' child activity and if it is in either the Initialized state
' or Closed state before closing the parent activity.
If (E.Activity.Equals(CustActivity.EnabledActivities(index)) And (E.ExecutionStatus = ActivityExecutionStatus.Closed Or E.ExecutionStatus = ActivityExecutionStatus.Initialized)) Then
' The child activities are now in a closed state, so it is
' safe to put your custom activity in a closed state as well.
Context.CloseActivity()
End If
End Sub
End Class
[Designer(typeof(ParallelActivityDesigner), typeof(IDesigner))]
public class CustomCompActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
{
// Declare variables.
private CodeActivity ca1;
private CodeActivity ca2;
private CodeActivity ca3;
private CodeActivity ca4;
private int index;
public CustomCompActivity()
{
InitializeComponent();
}
// Initialize your child activities and add them to your custom
// composite activity.
private void InitializeComponent()
{
this.CanModifyActivities = true;
this.ca1 = new CodeActivity("CodeActivity1");
this.ca2 = new CodeActivity("CodeActivity2");
this.ca3 = new CodeActivity("CodeActivity3");
this.ca4 = new CodeActivity("CodeActivity4");
ca1.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca2.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca3.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca4.ExecuteCode += new EventHandler(ca_ExecuteCode);
this.Activities.Add(ca1);
this.Activities.Add(ca2);
this.Activities.Add(ca3);
this.Activities.Add(ca4);
// Cache index value of last child activity in the collection.
index = this.Activities.Count - 1;
this.CanModifyActivities = false;
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (executionContext == null)
throw new ArgumentNullException("executionContext");
// If there are no child activities initialized, then close
// the parent activity.
if (this.EnabledActivities.Count == 0)
{
return ActivityExecutionStatus.Closed;
}
// Cycle through all of the enabled child activities in your
// activity, register for their Closed event, and then run the
// child activity.
for (int i = 0; i < this.EnabledActivities.Count; ++i)
{
Activity childActivity = this.EnabledActivities[i];
childActivity.RegisterForStatusChange(Activity.ClosedEvent, this);
childActivity.RegisterForStatusChange(Activity.ExecutingEvent, this);
executionContext.ExecuteActivity(childActivity);
}
return ActivityExecutionStatus.Executing;
}
// This event handler is used for the ExecuteCode event that
// each CodeActivity activity will raise during its execution.
void ca_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine ("In event handler for {0}.ExecuteCode event...", ((Activity)sender).Name);
}
// Implement the IActivityEventListener.OnEvent event handler to
// display the current activity state and close your parent custom
// activity when all of the child activities are either in the
// Initialized or Closed state. Otherwise, keep the parent activity
// running.
public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
if (sender == null)
throw new ArgumentNullException("sender");
if (e == null)
throw new ArgumentNullException("e");
ActivityExecutionContext context = sender as ActivityExecutionContext;
if (context == null)
throw new ArgumentException("The sender must be an ActivityExecutionContext object", "sender");
CustomCompActivity custActivity = context.Activity as CustomCompActivity;
// Display the current state of the child activity.
Console.WriteLine ("{0} is in the {1} state.", e.Activity.Name, e.ExecutionStatus);
// As a good coding practice, unregister for the Closed event
// if the child activity is in the closed state.
if (e.Activity.ExecutionStatus == ActivityExecutionStatus.Closed)
{
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
}
// Check whether the activity passed into the payload of the
// ActivityExecutionStatusChangedEventArgs object is the last
// child activity and if it is in either the Initialized state
// or Closed state before closing the parent activity.
if (e.Activity.Equals(custActivity.EnabledActivities[index]) && (e.ExecutionStatus == ActivityExecutionStatus.Closed || e.ExecutionStatus == ActivityExecutionStatus.Initialized))
{
// The child activities are now in a closed state, so it is
// safe to put your custom activity in a closed state as
// well.
context.CloseActivity();
}
}
}
通过使用上述示例,在工作流设计器内使用您的自定义活动时会将其锁定。 如果希望提供可以在设计时操作的具有子活动的自定义活动,则必须创建一个从 ActivityToolboxItem 派生的自定义类。
自定义工具箱项
下面的代码示例演示自定义复合活动的自定义工具箱项。 该工具箱项将一个 CodeActivity 活动添加到自定义复合活动中。
<Serializable()> _
Public Class SampleToolboxItem
Inherits ActivityToolboxItem
Protected Overrides Function CreateComponentsCore(ByVal designerHost As IDesignerHost) As IComponent()
Dim CompActivity As CustomCompositeActivity = New CustomCompositeActivity()
CompActivity.Activities.Add(New CodeActivity())
CompActivity.Activities.Add(New CodeActivity())
Return (New IComponent() {CompActivity})
End Function
End Class
[Serializable]
public class SampleToolboxItem: ActivityToolboxItem
{
protected override IComponent[] CreateComponentsCore(IDesignerHost designerHost)
{
CustomCompositeActivity CompActivity = new CustomCompositeActivity();
CompActivity.Activities.Add(new CodeActivity());
CompActivity.Activities.Add(new CodeActivity());
return new IComponent[] {CompActivity};
}
}
对您的自定义复合活动使用 SampleToolboxItem 时,必须通过 ToolboxItemAttribute 对其进行声明,如下面的示例所示。
<ToolboxItem(GetType(SampleToolboxItem))> _
[ToolboxItem(typeof(SampleToolboxItem))]
如上节所述,如果需要您的自定义复合活动的设计器显示子活动,如本示例中的 CodeActivity 活动,则您的自定义活动必须与类似 ParallelActivityDesigner 的复合活动设计器相关联,或者与派生自任意基础复合活动设计器类的自定义设计器相关联。
请参见
参考
CompositeActivity
SequenceActivity
CompositeActivityDesigner
ParallelActivityDesigner
SequentialActivityDesigner
ActivityToolboxItem
概念
其他资源
Windows Workflow Foundation 活动
版权所有 (C) 2007 Microsoft Corporation。保留所有权利。