使用活動委派
活動委派可讓活動作者使用特定的簽章以公開回呼,活動使用者可以此為依據來提供活動處理常式。 活動委派有兩種型別可用:ActivityAction<T>,用來定義沒有傳回值的活動委派,以及 ActivityFunc<TResult>,用來定義有傳回值的活動委派。
在限制子活動必須擁有簽章的案例中,活動委派非常實用。 例如,While 活動可包含任何沒有條件約束的子活動型別,但 ForEach<T> 活動的主體是 ActivityAction<T>,且最終由 ForEach<T> 執行的子活動,必須具有與 InArgument<T> 列舉之集合成員相同型別的 ForEach<T>。
使用 ActivityAction
有數個 .NET Framework 4.6.1 活動會使用活動的動作,例如 Catch 活動和 ForEach<T> 活動。 在每一個情況下,活動的動作都代表一個位置,工作流程作者會在這裡指定活動,以便在使用其中一個活動撰寫工作流程時提供所要的行為。 在下列範例中,ForEach<T> 活動是用來將文字顯示到主控台視窗。 ForEach<T> 的主體是使用符合字串 ActivityAction<T> 之型別的 ForEach<T> 所指定。 WriteLine 中指定的 Handler 活動擁有繫結至字串值的 Text 引數,該字串值位於 ForEach<T> 活動所反覆查看的集合中。
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
Activity wf = new ForEach<string>
{
Body = new ActivityAction<string>
{
Argument = actionArgument,
Handler = new WriteLine
{
Text = new InArgument<string>(actionArgument)
}
}
};
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
actionArgument 是用來將集合中的個別項目流動到 WriteLine。 當叫用此工作流程時,主控台就會顯示下列輸出。
HelloWorld.
本主題的範例會使用物件初始化語法。 物件初始化語法在使用程式碼建立工作流程定義時會很有用,因為它會在工作流程中提供活動的階層式檢視,並顯示活動之間的關係。 當您以程式設計方式來建立工作流程時,不一定非得使用物件初始化語法。 下列範例在功能上等同於先前的範例。
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);
ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;
ForEach<string> wf = new ForEach<string>();
wf.Body = body;
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
如需更多關於物件初始設定式的資訊,請參閱如何初始化物件但不呼叫建構函式 (C# 程式設計指南) 以及如何使用物件初始設定式宣告物件 (Visual Basic)。
在下列範例中,TryCatch 活動會用於工作流程中。 ApplicationException 是由工作流程所擲回而且是由 Catch<TException> 活動所處理。 Catch<TException> 活動的活動動作之處理常式是一種 WriteLine 活動,而例外狀況的詳細資料會透過 ex
DelegateInArgument<T> 流向它。
DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
Name = "ex"
};
Activity wf = new TryCatch
{
Try = new Throw()
{
Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Argument = ex,
Handler = new WriteLine()
{
Text = new InArgument<string>((env) => ex.Get(env).Message)
}
}
}
},
Finally = new WriteLine()
{
Text = "Executing in Finally."
}
};
建立定義 ActivityAction<T> 的自訂活動時,請使用 InvokeAction<T> 來建立該 ActivityAction<T> 的引動過程模型。 在這個範例中,會定義自訂 WriteLineWithNotification
活動。 此活動是由包含 Sequence 活動的 WriteLine 所構成,此活動之後是採用一個字串引數來叫用 InvokeAction<T> 的 ActivityAction<T>。
public class WriteLineWithNotification : Activity
{
public InArgument<string> Text { get; set; }
public ActivityAction<string> TextProcessedAction { get; set; }
public WriteLineWithNotification()
{
this.Implementation = () => new Sequence
{
Activities =
{
new WriteLine
{
Text = new InArgument<string>((env) => Text.Get(env))
},
new InvokeAction<string>
{
Action = TextProcessedAction,
Argument = new InArgument<string>((env) => Text.Get(env))
}
}
};
}
}
使用 WriteLineWithNotification
活動建立工作流程時,工作流程作者會在活動動作的 Handler 中指定想要的自訂邏輯。 在此範例中,會使用 WriteLineWithNotification
活動建立工作流程,且 WriteLine 活動會用來當做 Handler。
// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
Text = "Hello World."
};
WorkflowInvoker.Invoke(wf);
// Output:
// Hello World.
// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
Text = "Hello World with activity action.",
TextProcessedAction = new ActivityAction<string>
{
Argument = msg,
Handler = new WriteLine
{
Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
}
}
};
// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);
// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.
提供多個泛型版本的 InvokeAction<T> 和 ActivityAction<T>,以傳遞一個或多個引數。
使用 ActivityFunc
當活動沒有結果值時,ActivityAction<T> 會非常實用。當傳回結果值時,將會使用 ActivityFunc<TResult>。 建立定義 ActivityFunc<TResult> 的自訂活動時,請使用 InvokeFunc<TResult> 來建立該 ActivityFunc<TResult> 的引動過程模型。 在下列範例中,會定義 WriteFillerText
活動。 若要提供填入文字,應指定 InvokeFunc<TResult> 採用整數引數,並具有字串結果。 一旦擷取了填入文字之後,就會使用 WriteLine 活動將它顯示到主控台。
public class WriteFillerText : Activity
{
public ActivityFunc<int, string> GetText { get; set; }
public InArgument<int> Quantity { get; set; }
Variable<string> text = new Variable<string>
{
Name = "Text"
};
public WriteFillerText()
{
this.Implementation = () => new Sequence
{
Variables =
{
text
},
Activities =
{
new InvokeFunc<int, string>
{
Func = GetText,
Argument = new InArgument<int>((env) => Quantity.Get(env)),
Result = new OutArgument<string>(text)
},
new WriteLine
{
Text = new InArgument<string>(text)
}
}
};
}
}
若要提供文字,必須使用活動以採用一個 int
引數,並具有字串結果。 此範例顯示符合要求的 TextGenerator
活動。
public class TextGenerator : CodeActivity<string>
{
public InArgument<int> Quantity { get; set; }
public InArgument<string> Text { get; set; }
protected override string Execute(CodeActivityContext context)
{
// Provide a quantity of Random Text
int q = Quantity.Get(context);
if (q < 1)
{
q = 1;
}
string text = Text.Get(context) + " ";
StringBuilder sb = new StringBuilder(text.Length * q);
for (int i = 0; i < q; i++)
{
sb.Append(text);
}
return sb.ToString();
}
}
若要與 TextGenerator
活動共同使用 WriteFillerText
活動,請將它指定為 Handler。
DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();
Activity wf = new WriteFillerText
{
Quantity = 5,
GetText = new ActivityFunc<int, string>
{
Argument = actionArgument,
Handler = new TextGenerator
{
Quantity = new InArgument<int>(actionArgument),
Text = "Hello World."
}
}
};
WorkflowInvoker.Invoke(wf);