自訂活動是 Windows Workflow Foundation (WF) 實現領域邏輯封裝與重用的核心。本文基於 .NET Framework 3.0,系統闡述基本活動與複合活動的建構要點、非同步/事件驅動活動模式、設計時體驗客製化、以及驗證與錯誤處理機制,並以 CreateUserActivity (基本) 與 SwitchActivity (複合) 為實例贯穿始終。
protected override ActivityExecutionStatus Execute(ActivityExecutionContext context) {
var provider = String.IsNullOrEmpty(MembershipProviderName)
? Membership.Provider
: Membership.Providers[MembershipProviderName];
MembershipCreateStatus status;
provider.CreateUser(UserName, Password, Email, null, null, true, Guid.NewGuid(), out status);
return ActivityExecutionStatus.Closed; // 宣告完成
}
基本活動執行完畢即回傳 Closed,讓運行時排程下一個活動。
相依屬性 (DependencyProperty) 儲存於 DependencyObject 字典,支援:
public static DependencyProperty UserNameProperty = DependencyProperty.Register(
"UserName", typeof(string), typeof(CreateUserActivity));
[Description("此使用者的新使用者名稱")]
[Category("User")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string UserName {
get { return (string)base.GetValue(UserNameProperty); }
set { base.SetValue(UserNameProperty, value); }
}
原則:凡可能透過繫結受益的屬性,**一律使用相依屬性**。
SequenceActivity。SwitchActivity 模擬 C# switch:多個 SwitchBranchActivity (繼承 SequenceActivity + Condition 屬性),僅執行條件為 true 的分支。
protected override ActivityExecutionStatus Execute(ActivityExecutionContext context) {
foreach (Activity child in EnabledActivities) {
var branch = child as SwitchBranchActivity;
if (branch != null && branch.Condition.Evaluate(branch, context)) {
branch.Closed += OnChildClosed; // 註冊完成通知
context.ExecuteActivity(branch); // 排程執行
}
}
return ActivityExecutionStatus.Executing; // 尚未完成,等待子活動
}
void OnChildClosed(object sender, ActivityExecutionStatusChangedEventArgs e) {
var branch = sender as SwitchBranchActivity;
branch.Closed -= OnChildClosed;
// 檢查是否還有其他分支需執行 (Switch 僅執行一個,故直接關閉)
context.CloseActivity();
}
關鍵點:回傳 Executing 讓運行時暫停父流程;透過 IActivityEventListener 監聽子活動 Closed 事件;所有分支完成後呼叫 context.CloseActivity() 相當於回傳 Closed。
WF 運行時會閒置持久化工作流,**活動不可直接掛載外部事件處理常式** (持久化後會遺失)。解決方案:工作流佇列機制。
Execute 中建立/取得佇列 (WorkflowQueuingService),註冊 QueueItemAvailable 事件。Executing 等待外部觸發。FileSystemWatcher、WMI 事件),事件觸發時將資料入佇列 (Enqueue)。OnEvent 取出資料處理,呼叫 context.CloseActivity() 結束。IEventActivity:定義 Subscribe/Unsubscribe/QueueName,供運行時管理訂閱週期。IActivityEventListener<QueueEventArgs>:處理佇列項目可用通知。範例:ReadLineActivity(主控台輸入)、FileWatcherActivity(SDK 內建) 均採此模式。
HandleFault → 預設行為呼叫 Cancel 釋放資源。HandleFault 可執行特定清理 (釋放非受控資源、取消非同步操作)。Cancel 為主動式前向執行語義 (如 Parallel 取消其他分支);Fault 為被動式異常處理,兩者語義不同,勿混淆。ActivityDesigner)[Designer(typeof(MyDesigner), typeof(IDesigner))]。ActivityDesignerTheme 設定漸層色、前景色、圖示 (ToolboxBitmap)。Verbs 加入右鍵選單命令 (如「清除所有條件」)。DesignerVerbs (錯誤選單)、SmartTagVerbs (智慧標籤)。ParallelActivityDesigner (分支佈局) 或 FreeFormActivityDesigner (自由佈局)。ActivityDesigner 僅繪製單一圖塊。CanBeParentedTo:限制父活動類型 (如 SwitchBranch 僅允許在 Switch 下)。CanInsertActivities:限制可加入的子活動類型。ActivityValidator)編譯期與設計期皆執行,不受設計器限制。
public override ValidationErrorCollection Validate(ValidationManager manager, object obj) {
var errors = base.Validate(manager, obj);
var act = obj as CreateUserActivity;
if (act != null && act.Parent != null && !act.IsBindingSet(CreateUserActivity.PasswordProperty)) {
errors.Add(new ValidationError("密碼必須使用活動繫結設定", 1, false, "Password"));
}
return errors;
}
關聯:[ActivityValidator(typeof(CreateUserValidator))] 標記於活動類別。
WF 提供與內建活動同等的擴展點:從執行語義、設計器體驗、驗證規則到錯誤處理,開發者擁有完整控制權。建構健壯的活動庫,能將領域邏輯無縫整合進 WF 處理模型,充分發揮視覺化流程開發的價值。善用社群 (wf.netfx3.com) 分享與發現活動元件。