WF の仕組みとして TrackingRecord によるトラッキングの仕組みが用意されています。これはワークフローが、またはアクティビティが何か動作をするたびに通知されるレコードで、全部で 13 種類の状態が通知されます。各トラッキングレコードが何を伝えてくれるかは MSDN を参照してください。
TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 0, EventTime = 2011/05/02 9:59:55, ActivityDefinitionId = Sequence, State = Started }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 1, EventTime = 2011/05/02 9:59:55, Activity { Name=Sequence, ActivityId = 1, ActivityInstanceId = 1, TypeName=System.Activities.Statements.Sequence }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 2, EventTime = 2011/05/02 9:59:56, Activity { Name=Assign, ActivityId = 7, ActivityInstanceId = 2, TypeName=System.Activities.Statements.Assign }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 3, EventTime = 2011/05/02 9:59:56, Activity { Name=Assign, ActivityId = 7, ActivityInstanceId = 2, TypeName=System.Activities.Statements.Assign }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 4, EventTime = 2011/05/02 9:59:56, Activity { Name=Delay, ActivityId = 5, ActivityInstanceId = 3, TypeName=System.Activities.Statements.Delay }, State = Executing }
TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 5, EventTime = 2011/05/02 9:59:56, ActivityDefinitionId = Sequence, State = Idle }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 6, EventTime = 2011/05/02 9:59:57, Activity { Name=Delay, ActivityId = 5, ActivityInstanceId = 3, TypeName=System.Activities.Statements.Delay }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 7, EventTime = 2011/05/02 9:59:57, Activity { Name=メッセージを表示, ActivityId = 2, ActivityInstanceId = 4, TypeName=Workflow4.Command.DisplayActivity }, State = Executing }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 8, EventTime = 2011/05/02 9:59:58, Activity { Name=メッセージを表示, ActivityId = 2, ActivityInstanceId = 4, TypeName=Workflow4.Command.DisplayActivity }, State = Closed }
TrackingRecord : ActivityStateRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 9, EventTime = 2011/05/02 9:59:58, Activity { Name=Sequence, ActivityId = 1, ActivityInstanceId = 1, TypeName=System.Activities.Statements.Sequence }, State = Closed }
TrackingRecord : WorkflowInstanceRecord { InstanceId = c0c010f2-d75e-4084-a697-16951fde0a57, RecordNumber = 10, EventTime = 2011/05/02 9:59:58, ActivityDefinitionId = Sequence, State = Completed }
実際にトラッキングを行った際には、上記のようなレコードが通知されます。この内容は前回の記事で実際に実行した際の内容です。デザイナ上でトラッキング内容に基づいて表示を行うのですが、その前に追跡用のプロファイルを作成する必要があります。これは「何をトラッキングし通知するか」を設定するものです。
1: 'トラッキングプロファイルの生成
2: customTracker = New VisualTrackingParticipant '独自に用意したトラッキング用クラス
3: Dim trcProfile As New TrackingProfile With {.Name = "CustomTrackingProfile"}
4: 'トラッキングが必要なアクティビティの名前を設定
5: Dim ctQuery As New CustomTrackingQuery With {.Name = "*", .ActivityName = "*"}
6: trcProfile.Queries.Add(ctQuery)
7: 'トラッキングが必要なステータスを設定
8: Dim wfiQuery As New WorkflowInstanceQuery
9: wfiQuery.States.Add(WorkflowInstanceStates.Started)
10: wfiQuery.States.Add(WorkflowInstanceStates.Aborted)
11: wfiQuery.States.Add(WorkflowInstanceStates.Canceled)
12: wfiQuery.States.Add(WorkflowInstanceStates.Completed)
13: wfiQuery.States.Add(WorkflowInstanceStates.Idle)
14: wfiQuery.States.Add(WorkflowInstanceStates.Persisted)
15: wfiQuery.States.Add(WorkflowInstanceStates.Resumed)
16: wfiQuery.States.Add(WorkflowInstanceStates.Suspended)
17: wfiQuery.States.Add(WorkflowInstanceStates.Terminated)
18: wfiQuery.States.Add(WorkflowInstanceStates.UnhandledException)
19: wfiQuery.States.Add(WorkflowInstanceStates.Unloaded)
20: wfiQuery.States.Add(WorkflowInstanceStates.Unsuspended)
21: trcProfile.Queries.Add(wfiQuery)
22: 'ステータスのトラッキングが必要なアクティビティの名前を設定
23: Dim asQuery As New ActivityStateQuery With {.ActivityName = "*"}
24: asQuery.States.Add("*")
25: asQuery.Variables.Add("*")
26: trcProfile.Queries.Add(asQuery)
27:
28: customTracker.TrackingProfile = trcProfile
29: _wfApps.Extensions.Add(customTracker)
トラッキングプロファイルを設定するのはこのようなロジックとなります。作成したプロファイルを、WorkflowApplication の Extensions として追加していますが、これは WorkflowInvoker も同様です。
1: Imports System.Activities
2: Imports System.Activities.Tracking
3: Imports System.Collections.Generic
4:
5: Public Class VisualTrackingParticipant
6: Inherits Tracking.TrackingParticipant
7:
8: Public Event TrackingRecordReceived As EventHandler(Of TrackingEventArgs)
9:
10: Public Property ActivityIdToWorkflowElementMap As Dictionary(Of Integer, activity)
11: Public Property ActivityElementMap As Dictionary(Of Object, Debugger.SourceLocation)
12:
13: Protected Overrides Sub Track(ByVal record As System.Activities.Tracking.TrackingRecord, ByVal timeout As System.TimeSpan)
14: OnTrackingRecordReceived(record, timeout)
15: End Sub
16:
17: Protected Sub OnTrackingRecordReceived(ByVal record As TrackingRecord, ByVal timeout As TimeSpan)
18:
19: Dim resultArgs As New TrackingEventArgs With {.Record = record, .Timeout = timeout}
20: Select Case True
21: Case TypeOf record Is WorkflowInstanceRecord '100
22: Case TypeOf record Is WorkflowInstanceUnhandledExceptionRecord '101
23: Case TypeOf record Is WorkflowInstanceAbortedRecord '102
24:
25: Case TypeOf record Is ActivityStateRecord '103
26: If ActivityIdToWorkflowElementMap.ContainsKey(DirectCast(record, ActivityStateRecord).Activity.Id) Then
27: resultArgs.Activity = ActivityIdToWorkflowElementMap.Item(DirectCast(record, ActivityStateRecord).Activity.Id)
28: End If
29: Case TypeOf record Is ActivityScheduledRecord '104
30: If ActivityIdToWorkflowElementMap.ContainsKey(DirectCast(record, ActivityScheduledRecord).Activity.Id) Then
31: resultArgs.Activity = ActivityIdToWorkflowElementMap.Item(DirectCast(record, ActivityScheduledRecord).Activity.Id)
32: End If
33: Case TypeOf record Is FaultPropagationRecord '105
34: Case TypeOf record Is CancelRequestedRecord '106
35: Case TypeOf record Is BookmarkResumptionRecord '107
36: Case TypeOf record Is CustomTrackingRecord '108,110,111
37:
38: Case TypeOf record Is WorkflowInstanceSuspendedRecord '112
39: Case TypeOf record Is WorkflowInstanceTerminatedRecord '113
40:
41: End Select
42: RaiseEvent TrackingRecordReceived(Me, resultArgs)
43:
44: End Sub
45: End Class
46:
独自に用意したトラッキング用クラスはこのようなロジックで行っています。内容としては対象アクティビティが関連する ActivityStateRecord や ActivityScheduledRecord が通知された際に、TrackingRecord の内容から対象アクティビティを確定させてイベントに通知させることを行っています。イベント受け取り側ではこの内容を元に、WorkflowDesigner.DevugManagerView.CurrentLocation にその時点でのアクティビティを設定する事で、デザイナ上に黄色い枠線で囲まれて表示が行われるようになります。