2011-09-06 59 views
1

我试图让Windows工作流程工作,并且我变得有点难住了。如何将参数传递给NativeActivity代码序列中的CodeActivity

我已经获得了一个工作流程,但现在我正在尝试做一些更复杂的事情:启动一个工作流程,其中每个活动本身都包含一个工作流程。 (图片类似于主程序启动“输入,逻辑和输出”活动,然后每个人都有附加活动,如“提示用户,获取输入等”)

我已经有它工作正常,从这里的例子(http://msdn.microsoft.com/en-us/magazine/gg535667.aspx),当我没有从主程序传递任何参数到activites。我的问题是,'变量'和'metadata.SetVariablesCollection'在NativeActivity中如何工作,以及如何将参数传递给低级活动?

这是我目前正在:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Activities; 
using System.Collections.ObjectModel; 
using System.Activities.Statements; 

namespace Project1 
{ 
    internal class MainProgram 
    { 
     internal static void Main(string[] args) 
     { 
      try 
      { 
       var act = new SimpleSequence(); 

       act.Activities.Add((Activity)(new WriteSomeText())); 
       act.Activities.Add((Activity)(new WriteSomeText())); 
       act.Activities.Add((Activity)(new WriteSomeText())); 

       act.Variables.Add(new Variable<string> ("stringArg", "TEXT")); 

       WorkflowInvoker.Invoke(act); 
      } 
      catch (Exception ex) 
      { 
       System.Console.WriteLine("EXCEPTION: {0}", ex); 
      } 
     } 

     public class WriteSomeText : CodeActivity 
     { 
      [RequiredArgument] 
      public InArgument<string> stringArg { get; set; } 

      protected override void Execute(CodeActivityContext context) 
      { 
       string output = context.GetValue(stringArg); 
       System.Console.WriteLine(output); 
      } 

     } 

     public class SimpleSequence : NativeActivity 
     { 
      Collection<Activity> activities; 
      Collection<Variable> variables; 

      Variable<int> current = new Variable<int> { Default = 0 }; 

      public Collection<Activity> Activities 
      { 
       get 
       { 
        if (this.activities == null) 
         this.activities = new Collection<Activity>(); 

        return this.activities; 
       } 
       set 
       { 
        this.activities = value; 
       } 
      } 

      public Collection<Variable> Variables 
      { 
       get 
       { 
        if (this.variables == null) 
         this.variables = new Collection<Variable>(); 

        return this.variables; 
       } 
       set 
       { 
        this.variables = value; 
       } 
      } 

      protected override void CacheMetadata(NativeActivityMetadata metadata) 
      { 
       metadata.SetChildrenCollection(this.activities); 
       metadata.SetVariablesCollection(this.variables); 
       metadata.AddImplementationVariable(this.current); 
      } 

      protected override void Execute(NativeActivityContext context) 
      { 
       if (this.Activities.Count > 0) 
        context.ScheduleActivity(this.Activities[0], onChildComplete); 
      } 

      void onChildComplete(NativeActivityContext context, ActivityInstance completed) 
      { 
       int currentExecutingActivity = this.current.Get(context); 
       int next = currentExecutingActivity + 1; 

       if (next < this.Activities.Count) 
       { 
        context.ScheduleActivity(this.Activities[next], this.onChildComplete); 

        this.current.Set(context, next); 
       } 
      } 
     } 
    } 
} 

这最终引发了以下异常:

EXCEPTION: System.Activities.InvalidWorkflowException: The following errors were encountered while processing the workflow tree: 
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied. 
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied. 
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied. 
    at System.Activities.Validation.ActivityValidationServices.ThrowIfViolationsExist(IList`1 validationErrors) 
    at System.Activities.Hosting.WorkflowInstance.ValidateWorkflow(WorkflowInstanceExtensionManager extensionManager) 
    at System.Activities.Hosting.WorkflowInstance.RegisterExtensionManager(WorkflowInstanceExtensionManager extensionManager) 
    at System.Activities.WorkflowApplication.EnsureInitialized() 
    at System.Activities.WorkflowApplication.RunInstance(WorkflowApplication instance) 
    at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout) 
    at System.Activities.WorkflowInvoker.Invoke(Activity workflow, TimeSpan timeout, WorkflowInstanceExtensionManager extensions) 
    at System.Activities.WorkflowInvoker.Invoke(Activity workflow) 
    at Project1.MainProgram.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ModelingProject1\Project1\MainProgram.cs:line 25 

我知道,我只通过1个参数,但异常仍说我我缺少3个参数。我错过了如何正确地做到这一点。

回答

1

你正确声明stringArg作为InArgument但里面调用它时SimpleSequence你不传递任何价值了。

您可以使用构造函数,而构建的所有活动本身,这样传递的东西:

public class WriteSomeText : CodeActivity 
{ 
    [RequiredArgument] 
    public InArgument<string> stringArg { get; set; } 

    public WriteSomeText(string stringArg) 
    { 
     this.stringArg = stringArg; 
    } 

    protected override void Execute(CodeActivityContext context 
    { 
     string output = context.GetValue(stringArg); 
     System.Console.WriteLine(output); 
    } 
} 

// Calling the activity like this: 

internal static void Main(string[] args) 
{ 
    var act = new SimpleSequence() 
    { 
     Activities = 
     { 
      new WriteSomeText("hello"), 
      new WriteSomeText("world"), 
      new WriteSomeText("!") 
     } 
    }; 

    WorkflowInvoker.Invoke(act); 

    Console.WriteLine("Press any key to exit"); 
    Console.ReadKey(); 
} 

还要注意的是使用构造函数初始化集合最佳实践:

public SimpleSequence() 
{ 
    activities = new Collection<Activity>(); 
    variables = new Collection<Variable>(); 
} 

这种方式更加直观地初始化活动:

var act = new SimpleSequence() 
{ 
    Activities = 
    { 
     new WriteSomeText("hello"), 
     new WriteSomeText("world"), 
     new WriteSomeText("!") 
    }, 
    Variables = 
    { 
     new Variable<int>("myNewIntVar", 10), 
     // .... 
    } 
}; 

编辑:

有几种其他方法来解决这个问题。 This是您在WF4世界中开始的最好的朋友。

检查WF \ Basic \ CustomActivities \ Code-Bodied对于这种特殊情况的一点点推动。

+0

当* SimpleSequence *中的下一个活动是* WriteSomeText *时,您也可以对* stringArg *进行硬编码,但这远不是最佳做法。 **硬编码**是一个信号。 – Joao

+0

谢谢你,但我的问题就变成了,SimpleSequence中“Variables”变量的重点是什么?如果所有的代码活动在施工过程中都得到它们的参数,那么它的预期用途是什么? – Curtor

+0

您必须将*变量 *作为常规方法中的局部变量,用于临时操作和保存数据**。在构建自定义活动时就像提供要使用的方法一样。您不希望用户在您的方法中触摸局部变量(无论是使用常规编程语言还是使用WF4本身)。对同一方法的任何输入都通过* InArgument *给出,它与方法中的参数声明相对应。 – Joao