和.NET Framework中提供Action<T>和Func<>系列类似,只不过这个是构建在WF引擎之上的,利用该特性可以在我们开发的通用的流程中,可以让用户加入自己的业务逻辑。
下面是一个简单的例子
1. 首先开发一个自定义活动如下:
public class CaryActivity : NativeActivity
{
public ActivityAction<string> customAction { get; set; }
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
metadata.AddDelegate(customAction);
}
protected override void Execute(NativeActivityContext context)
{
context.ScheduleAction<string>(customAction, "custom action",new CompletionCallback(this.onCompleted),null);
}
public void onCompleted(NativeActivityContext context, ActivityInstance completedInstance)
{
Console.WriteLine("onCompleted");
}
}
2. 我们在活动中定义了一个ActivityAction,用户在使用该活动的时候就可以加入自己的逻辑。如下
class Program
{
static void
{
DelegateInArgument<string> argument = new DelegateInArgument<string>("itemtest");
CaryActivity caryac = new CaryActivity()
{
customAction = new ActivityAction<string>()
{
Argument = argument,
Handler = new WriteLine() { Text = new InArgument<string>((context) => "This is " + argument.Get(context)) }
}
};
WorkflowInvoker.Invoke(caryac);
Console.ReadLine();
}
}
3. WF4自己提供很多开箱即用的活动,都使用该特性,比如我们可以利用Reflector来看下ForEach的代码如下:
[ContentProperty("Body")] public sealed class ForEach : NativeActivity { // Fields [CompilerGenerated] private ActivityAction<object> <Body>k__BackingField; [CompilerGenerated] private InArgument<IEnumerable> <Values>k__BackingField; private CompletionCallback onChildComplete; private Variable<IEnumerator> valueEnumerator = new Varriable<IEnumerator>(); // Methods protected override void CacheMetadata(NativeActivityMetadata metadata) { RuntimeArgument argument = new RuntimeArgument("Values", typeof(IEnumrerable), ArgumentDirection.In, true); metadata.Bind(this.Values, argument); metadata.AddArgument(argument); metadata.AddDelegate(this.Body); metadata.AddImplementationVariable(this.valueEnumerator); } protected override void Execute(NativeActivityContext context) { IEnumerable enumerable = this.Values.Get(context); if (enumerable == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ForEachRequiresNonNullValues(base.DisplayName))); } IEnumerator enumerator = enumerable.GetEnumerator(); this.valueEnumerator.Set(context, enumerator); if ((this.Body == null) || (this.Body.Handler == null)) { while (enumerator.MoveNext()) { } this.OnForEachComplete(enumerator); } else { this.InternalExecute(context, enumerator); } } private void GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance) { IEnumerator valueEnumerator = this.valueEnumerator.Get(context); this.InternalExecute(context, valueEnumerator); } private void InternalExecute(NativeActivityContext context, IEnumerator valueEnumerator) { if (!valueEnumerator.MoveNext()) { this.OnForEachComplete(valueEnumerator); } else if (context.ExecutingActivityInstance.IsCancellationRequested) { context.MarkCanceled(); this.OnForEachComplete(valueEnumerator); } else { context.ScheduleAction<object>(this.Body, valueEnumerator.Current, this.OnChildComplete, null); } } private void OnForEachComplete(IEnumerator valueEnumerator) { IDisposable disposable = valueEnumerator as IDisposable; if (disposable != null) { disposable.Dispose(); } } // Properties [DefaultValue((string) null), DependsOn("Values")] public ActivityAction<object> Body { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.<Body>k__BackingField; } [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set { this.<Body>k__BackingField = value; } } private CompletionCallback OnChildComplete { get { if (this.onChildComplete == null) { this.onChildComplete = new CompletionCallback(this.GetStateAndExecute); } return this.onChildComplete; } } [RequiredArgument, DefaultValue((string) null)] public InArgument<IEnumerable> Values { [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get { return this.<Values>k__BackingField; } [CompilerGenerated, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set { this.<Values>k__BackingField = value; } } } |
以看到他的Body就是一个ActivityAction,去执行用户自己指定的Body部分活动,并循环去枚举直到其中的逻辑执行完成为止。
参考资源:
http://blogs.msdn.com/mwinkle/archive/2009/12/24/swiss-cheese-and-wf4-or-an-introduction-to-activityaction.aspx
http://blogs.msdn.com/mwinkle/archive/2010/01/15/making-swiss-cheese-look-good-or-designers-for-activityaction-in-wf4.aspx
http://msdn.microsoft.com
http://social.msdn.microsoft.com/Forums/en-US/wfprerelease/threads