SharePoint 2010 状态机工作流,带自定义任务表单(InfoPath),使用 VS 2010 - 第 1 部分,共 3 部分






4.79/5 (15投票s)
本教程介绍如何在 SharePoint 2010 中使用 InfoPath 2010 构建自定义状态机工作流和自定义任务窗体。这是一个基于示例的教程,我将模拟一个组织的招聘流程。
第 1 部分:构建自定义 SharePoint 2010 工作流
第 2 部分:配置和部署自定义 InfoPath 任务窗体
第 3 部分: 将数据从 SharePoint 工作流发送到 InfoPath 窗体
引言
工作流是管理业务流程执行的系统。它们主要被描述为管理各种个人、部门或多个组织之间工作流程的流程。
与仅向前推进且从不回退的顺序工作流(尽管可以使用 while
循环多次重复相同的步骤)相比,状态机工作流从一个状态移动到另一个状态,直到工作流达到完成状态并结束。
有三种不同类型的工作流
- 开箱即用的工作流
- SharePoint Designer 工作流
- 在 Visual Studio 中构建的自定义工作流
可以使用 Visual Basic 或 Visual C# 在 Visual Studio 中开发 SharePoint 工作流。在本教程中,我们将模拟一个组织的招聘流程。
我们的工作流将包含以下步骤
- 收到面试申请
- 初步审核
- 技术审核
- 人事审核
- 已录用
- 已拒绝
- Completed
在开始工作流之前,我们必须在 SharePoint 应用程序中有一个名为 Candidates
的列表(或库)。与该列表相关的元数据将包含以下列
- 标题
- 技术栈
- 经验(月)
- 状态
您可以根据需要添加列。状态机工作流本质上是事件驱动的工作流。我们创建一个任务并为其附加一个事件处理程序。然后我们等待任务完成,在任务完成后;我们根据用户输入做出决定。
必备组件
- .NET(实现是用 C# 编写的)
- SharePoint 对象模型
实现
步骤 1
在 Visual Studio 中,选择 SharePoint 2010 状态机工作流模板。填写名称和解决方案等详细信息,然后单击“确定”。请参阅图 1.1。
在下一个窗口中,输入工作流要运行的网站 URL,然后单击“下一步”按钮。工作流只能作为场解决方案部署,因此我们没有将其部署为沙盒解决方案的选项。在下一个窗口中,为工作流命名,并选择要创建的工作流类型。在本例中,我们将选择列表工作流。
下一个窗口提供将工作流与列表或文档库关联的选项。如果取消选中关联复选框,我们可以选择不关联工作流。在这种情况下,我们以后必须手动将工作流与列表或库关联。在本例中,我们将工作流与 Candidates
列表关联。
下一个窗口允许我们为工作流设置触发器。在本例中,我们希望工作流在 Candidates
列表中的项目创建时自动启动。因此,我们将选择该选项并单击“完成”按钮。
第二步
让我们仔细看看解决方案资源管理器。
IDE 会自动将工作流所需的引用添加到解决方案中。我们可以根据需要手动添加引用。
Feature1
是将部署我们工作流的功能。可以从站点设置中激活和停用此功能。
Elements.xml 将用于配置我们工作流的各种属性。我们将在教程的后续部分详细介绍此文件。
Workflow1.cs 是我们工作流的后台代码文件。所有服务器端代码都保存在此文件中。请参阅图 1.2。
在我们继续之前,我们需要配置工作流的功能接收器。为此,请单击工作流设计文件并按“F4”。这将打开工作流的属性窗口。在属性窗口中,我们可以看到“功能接收器”属性。打开该属性的树节点,它有两个属性:程序集(Assembly)和类名(Class Name)。
请为这些属性键入以下值。请务必查找 Microsoft.Office.Workflow.Feature
可用的程序集最新版本以及与之相关的公钥令牌。
对于程序集
Microsoft.Office.Workflow.Feature, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c
对于类名
Microsoft.Office.Workflow.Feature.WorkflowFeatureReceiver
步骤 3
现在我们将设计工作流。在工作流的设计器表面,拖放 State
活动。如前所述,我们有 9 个活动,总共拖放 9 个 State
活动,并为它们指定适当的名称。请参阅图 1.3。
我们需要为工作流设置一个初始状态和一个完成状态。由于我们希望“InterviewApplicationReceived
”状态是我们的初始状态,请右键单击它,然后在上下文菜单中选择“设为初始状态”。同样,右键单击“Completed
”状态并选择“设为完成状态”。这将使“Completed
”状态成为工作流的最终状态。
步骤 4
我们需要启动我们的工作流。要启动工作流,我们将一个 EventDrivenActivity
拖放到工作流的初始状态,即“InterviewApplicationReceived
”状态。有两种方法可以将事件驱动活动添加到我们的状态。您可以从工具箱中拖放活动,或者简单地右键单击状态并在上下文菜单中单击“添加 EventDriven
”。
添加活动后,双击该活动以转到活动详细信息,从属性窗口为其指定一个适当的名称。在我们的工作流中,我们将其命名为“eventDrivenActivityInitial
”。
下一步是将 OnWorkflowActivated
事件处理程序拖放到我们的事件驱动活动中。从工具箱将 OnWorkflowActivated
事件处理程序拖放到活动画布上。属性窗口显示与事件处理程序关联的属性。
让我们看一下 OnWorkflowActivated
事件处理程序的属性。其中大多数属性对于所有事件处理程序活动都是通用的。请参阅图 1.4。
工作流实例在其生命周期中与多个 SharePoint 对象(任务列表、文档或项目)进行交互。在 SharePoint 中,可以同时运行许多工作流实例,并同时与多个对象进行交互。为了能够识别哪个工作流实例正在与哪个对象交互,您必须使用一个标识符来链接特定的工作流实例和一个特定的 SharePoint 对象。每个工作流实例都必须绑定到其自己的项目。 such identifier is called a Correlation Token。关联令牌将工作流实例与其文档、项目和任务链接起来。它防止不同工作流实例之间的混淆。我们需要为工作流有一个关联令牌,并为我们在工作流中创建的每个任务创建一个关联令牌,以便当用户完成任务时,我们有一个唯一的标识符可以接收用户输入到工作流。确保关联令牌的名称在不同任务中不重复。键入“InitialToken
”(尽管令牌的名称可以是您想要的任何名称,但我们通常倾向于使用任务名称后跟 Token 的命名约定)。将所有者活动设置为“InterviewApplicationReceived
”状态。
当工作流激活时,将触发 OnWorkflowActivated
的“调用”(Invoked)事件。此时,我们不会在此方法中添加任何实现逻辑。在这种情况下,我们使用“onWorkflowActivatedInitial_Invoked
”作为方法名。当您在键入方法名后按 Tab 键时,Visual Studio IDE 将在后台代码文件中创建一个事件处理程序块。
接下来,单击 WorkflowProperties
属性中的省略号。这将打开一个弹出窗口,在“绑定到现有成员”(Bind to an existing member)选项卡中,选择 workflowProperties
。如果 workflowProperties
在此选项卡中找不到,请移至下一个选项卡,即“绑定到新成员”(Bind to a new member),选择“创建字段”(Create Field)单选按钮,然后在新成员名称文本框中键入“workflowProperties
”,然后按“确定”。
接下来,将“SetState
”活动(从工具箱的 3.0 选项卡中选择;SharePoint 选项卡中也有 SetState
)拖放到事件处理程序下方。将目标状态名称设置为“Initial Clearance”状态。这样就完成了初始状态的配置。
步骤 5
现在让我们配置“Initial Clearance”状态。在这里,我们将添加 StateInitialization
活动。在 StateInitialization
活动中,我们将创建任务,并配置参与者、截止日期等详细信息。
因此,拖动一个 StateInitialization
活动(从工具箱的 3.0 选项卡中拖动)并将其放入“Initial Clearance”状态内。我们将此活动命名为“stateInitializationInitialClearanceActivity
”。双击该活动,然后从工具箱的 SharePoint 选项卡中拖动“Create Task”活动并将其放入状态初始化活动中。
我们将“Create Task”活动命名为“createTaskInitialClearance
”。
通过在属性窗口中键入令牌名称来创建新的关联令牌。我们将令牌命名为“InitialClearanceToken
”,并将所有者活动设置为“Initial Clearance”状态。
我们需要将一个方法与“方法调用”(Method Invoking)事件绑定。在本例中,用于方法调用事件的命名约定是任务名称后跟一个下划线(_)和一个 methodInvoking
。因此,对于“Initial Clearance”任务,方法名称将是“createTaskInitialClearance_MethodInvoking
”。
接下来,我们需要设置 TaskId
和 TaskProperties
的值。单击 TaskId
属性中的省略号。它会打开一个弹出窗口。在“绑定到新成员”(Bind to a new member)选项卡中,选择“创建字段”(Create Field)单选按钮。在文本框中输入名称,然后单击“确定”。我们创建一个名为“createTaskInitialClearanceTaskId
”的 TaskId
。
同样,对于 TaskProperties
,创建一个名为“createTaskInitialClearanceTaskProperties
”的新字段(而不是属性)。这样,我们就完成了“Create Task”和“State Initialization”的配置。
步骤 6
拖动一个“Event Driven”活动(从工具箱的 3.0 选项卡中拖动)并将其放入“Initial Clearance”状态内。将其命名为“eventDrivenActivityInitialClearance
”。
双击“Event Driven”活动,然后从工具箱的 SharePoint 选项卡中拖动 OnTaskChanged
活动并将其命名为“onTaskChangedInitialClearance
”。
为 AfterProperties
和 BeforeProperties
创建字段(遵循与创建 TaskId
和 TaskProperties
类似的步骤),分别命名为“onTaskChangedInitialClearanceAfterProperties
”和“onTaskChangedInitialClearanceBeforeProperties
”。
现在,在“关联令牌”(Correlation Token)字段中,选择我们已与“Create Task”活动关联的相同令牌。这允许工作流实例了解此事件处理程序与哪个任务相关联。在本例中,我们将选择“InitialClearanceToken
”作为关联令牌。大多数工作流错误都与不正确地分配关联令牌有关。因此,我们在处理关联令牌时需要格外小心。
将一个方法与活动的“调用”(Invoked)事件关联,我们在其中键入“onTaskChangedInitialClearance_Invoked
”作为方法名。我们还需要为此活动绑定 TaskId
,但我们不会创建新的 TaskId
,而是绑定我们在“Create Task”活动中创建的 TaskId
。为此,请在弹出窗口中选择“绑定到现有成员”(Bind to an existing member)选项卡,选择我们在“Create Task”活动中创建的 TaskId
,然后单击“确定”。
为了回顾我们到目前为止所取得的成就:我们创建了 State
,添加了 StateInitialization
活动。在 StateInitialization
活动中,我们创建了一个 Task
并为其分配了一个关联令牌。在 CreateTask
活动的“方法调用”(Method Invoking)事件上,我们关联了一个方法。我们将在该方法中编写一些逻辑。然后,我们在 State
中添加了一个 EventDriven
活动。在 EventDriven
活动中,我们拖放了一个 OnTaskChanged
活动。我们为该活动创建了所需的字段,并为其分配了与我们在 CreateTask
活动中创建的关联令牌相同的令牌。我们将一个方法与 OnTaskChanged
活动的“调用”(Invoked)事件关联。当用户执行分配给他的任务时,将触发此方法。
步骤 7
现在,一旦用户执行了任务,在这种情况下,当用户指示收到的简历是批准还是拒绝时,我们需要执行一些操作。
默认的任务列表项如图 1.5 所示。我们可以自定义任务列表项,并使用 InfoPath
窗体或 ASPX 窗体而不是默认的任务列表项。
现在,如果用户在任务的描述列中键入“Approved
”,我们将继续工作流的下一步;否则,我们将停止工作流。因此,我们将一个 IfElse
活动(从工具箱的 3.0 选项卡中拖动)放在 OnTaskChanged
活动下方,位于 EventDriven
活动内部。
选择 IfElseBranchActivity1
,在属性窗口中有一个 Condition
属性,选择“代码条件”(Code Condition)作为条件。打开 Condition
树节点,在左侧节点属性中,键入将包含处理条件逻辑的方法的名称。在本例中,我们将“InitialClearanceApprovalProcess
”键入为代码条件。
现在,将 SetState
活动(从工具箱的 3.0 选项卡中拖动)放入 IfElseBranchActivity1
中,并将下一个状态选作 TargetStateName
。在本例中,“TechnicalClearance
”将是目标状态。将 IfElseBranchActivity2
保持原样。
步骤 8
我们完成了此状态工作流的设计部分,现在我们需要编写后台代码文件中的逻辑。
因此,右键单击设计器并从上下文菜单中选择“查看代码”(View Code),或者在设计器表面简单按 F7。您可以看到我们从设计器表面创建的所有字段和方法都已在后台代码文件中创建。
第一个方法与 OnWorkflowActivated
活动相关联。目前,我们不会在此方法中添加任何实现逻辑。
接下来,是与“Initial Clearance”状态 ->“State Initialization”->“Create Task”相关联的方法。我们已将方法“createTaskInitialClearance_MethodInvoking
”与此事件关联。在此事件中,我们将配置任务的标题、执行任务的用户或组、任务的截止日期以及其他此类详细信息。
private void createTaskInitialClearance_MethodInvoking(object sender, EventArgs e)
{
try
{
//Create a new TaskId for the Task
this.createTaskInitialClearanceTaskId = Guid.NewGuid();
//TaskProperties field is used to configure the Task Details.
this.createTaskInitialClearanceTaskProperties.Title =
"Initial Clearance";
//You can assign a Task to a user or to a group.
//Here we assign the task to HR-Group
this.createTaskInitialClearanceTaskProperties.AssignedTo = "HRGroup";
this.createTaskInitialClearanceTaskProperties.DueDate =
DateTime.Today.AddDays(5.0);
}
catch (Exception ex)
{
//Logging is used so that we can debug the errors in the workflow.
System.Diagnostics.EventLog.WriteEntry("Recruitment Workflow",
ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
LogToHistoryListActivity log = new LogToHistoryListActivity();
log.HistoryDescription = ex.StackTrace;
}
}
接下来,是与“Initial Clearance”状态 ->“Event Driven”-> OnTaskChanged
相关联的方法。我们已将方法“onTaskChangedInitialClearance_Invoked
”与此事件关联。在此方法中,我们将编写用户完成任务后要遵循的处理逻辑。
如果我们查看 onTaskChangedInitialClearanceAfterProperties
和 onTaskChangedInitialClearanceBeforeProperties
字段,它们是 SPWorkflowTaskProperties
类的对象。顾名思义,此类表示工作流任务的属性。我们将任务中的值分配给这些对象,以便我们可以在其他方法中使用它们。
在本例中,我们将通过将 PercentComplete
属性的值设置为 1.0
来将任务标记为完成。
private void onTaskChangedInitialClearance_Invoked
(object sender, ExternalDataEventArgs e
{
try
{
this.onTaskChangedInitialClearanceAfterProperties =
this.onTaskChangedInitialClearance.AfterProperties;
this.onTaskChangedInitialClearanceBeforeProperties =
this.onTaskChangedInitialClearance.BeforeProperties;
//Set the PercentComplete property to 1.0 (i.e. 100%)
//to indicate that the task has been completed.
this.onTaskChangedInitialClearanceAfterProperties.PercentComplete =
(float)1.0;
}
catch (Exception ex)
{
…
}
}
现在,我们将实现代码条件的逻辑。IfElse
活动的任务已与 InitialClearanceApprovalProcess
方法相关联。
private void InitialClearanceApprovalProcess(object sender, ConditionalEventArgs e)
{
try
{
if (this.onTaskChangedInitialClearanceAfterProperties.
PercentComplete == 1.0)
{
if (this.onTaskChangedInitialClearanceAfterProperties.
Description.Contains("Approved"))
{
e.Result = true;
}
else
{
e.Result = false;
}
}
else
{
e.Result = false;
}
}
catch (Exception ex)
{
…
}
}
如果用户在任务项的描述字段中键入“Approved
”,我们将 if
-else
的结果设置为 true
,否则将结果设置为 false
。在本教程的后续部分,我们将看到如何使用自定义任务窗体来获取这些值。这样,我们就可以有一个下拉控件供用户选择候选人是批准还是拒绝。
步骤 9
这就是我们为完全配置一个任务需要编写的所有代码。执行步骤 5 到步骤 8 以完成其余任务。您可以在下方(图 1.6)看到完成的工作流的快照。
构建并部署工作流。
第 2 部分介绍如何在 InfoPath 2010 中生成自定义任务窗体,并将这些窗体与工作流中的每个任务关联。
历史
- 2011 年 5 月 9 日:初稿。
- 2012 年 1 月 17 日:已解决源代码中的一个错误。