65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Visual Studio 2010 构建 SharePoint 2010 状态机工作流与自定义任务表单 (InfoPath):第 2 部分(共 3 部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (12投票s)

2011 年 5 月 12 日

CPOL

9分钟阅读

viewsIcon

207028

downloadIcon

2535

本教程介绍 SharePoint 2010 自定义状态机工作流以及 InfoPath 2010 中的自定义任务窗体。本教程基于示例,我将模拟一个组织的招聘流程。

第一部分: 构建自定义 SharePoint 2010 工作流

第二部分: 配置和部署自定义 InfoPath 任务窗体 

第三部分: 将数据从 SharePoint 工作流发送到 InfoPath 窗体 

介绍 

正如教程的第一部分所述,我们可以使用自定义任务窗体而不是 SharePoint 提供的默认任务窗体。默认窗体具有固定的字段数量,无法更改。使用自定义窗体,我们可以从用户那里收集所需信息,并且它们还可以使过程更加动态和灵活。

在本教程的这一部分,我们将介绍如何使用 InfoPath 2010 设计自定义工作流任务窗体。InfoPath 提供了更丰富的交互体验,用户可以与工作流进行交互。

为了处理 InfoPath 中的自定义任务窗体,SharePoint 2010 将显示工作流窗体的超链接链接到一个包含 Office Forms Services Web 部件的 ASPX 页面。处理窗体的逻辑编写在此 Web 部件中。此 Web 部件已配置为可以接收和提交数据。因此,如果我们想在 InfoPath 窗体中显示来自 SharePoint 列表(或库)的某些信息,我们将在 InfoPath 窗体中创建一个“接收数据”连接。类似地,要将数据从 InfoPath 窗体复制到 SharePoint 列表(或库),我们会创建一个“提交数据”连接。

我们在工作流模板定义(即 Elements.xml)中指定我们要使用的自定义窗体,而不是在工作流本身中。这涉及设置两个元素:窗体 URL 和自定义 InfoPath 2010 窗体的 URN。窗体 URL 需要与适当的工作流进程相关联,例如关联、初始化、修改等。此链接很重要,以便 SharePoint 中包含相应的 ASPX 托管页面。接下来,您将添加一个元素来指定该类型工作流进程的自定义 InfoPath 2010 窗体的 URN。

在继续之前,我们将向 SharePoint 列表添加一些其他列。更新后的列表具有以下列

  1. 标题
  2. 技术栈
  3. 总经验
  4. 候选人状态
  5. 初步评价
  6. 技术面试评价
  7. 人力资源评价
  8. 初步审核人
  9. 初步审核日期
  10. 技术审核日期
  11. 人力资源面试官
  12. 人力资源审核日期
  13. 技术面试分配给

设计

让我们开始设计第一个任务的 InfoPath 窗体,即初步审核。

打开 Microsoft InfoPath Designer 2010;在“新建”选项卡中双击一个空白窗体。这将打开一个带有空白窗体的窗口。对于初步审核任务,我们将为用户提供批准或拒绝候选人的选项。如果用户选择批准候选人,那么他/她将必须指定一个技术面试小组和一个人力资源面试小组,否则用户将输入拒绝的评论,然后工作流终止。

设计您想用于任务窗体的表格结构。您可以使用“页面设计”选项卡中的“页面布局”中提供的预定义结构。在 InfoPath Designer 的“数据”选项卡中,单击“显示字段”按钮。

根据需要将控件拖放到窗体上。在页面底部,我们将有一个按钮控件,它将在 InfoPath 中触发“提交”规则。

要为“状态”下拉列表添加值,请右键单击“状态”下拉列表并选择“下拉列表框属性”。使用“属性”,您可以根据需要添加或修改值。相应地重命名字段,因为我们将在 Visual Studio 的代码隐藏文件中使用这些名称。

我们的 InfoPath 窗体上还有一个联系人选择器。要将联系人选择器配置为使用 SharePoint 中的用户,请右键单击控件并转到“属性”。在“SharePoint 服务器”选项卡中,输入 SharePoint 站点的 URL。这样,控件就可以从 SharePoint 中获取用户。

图 1.1

用户单击“完成任务”按钮后,我们将需要关闭窗口。因此,在“规则浏览器”中,再次单击“添加”按钮并选择“关闭窗体”选项。您可以预览窗体并进行相应更改。有关完整的 InfoPath 窗体,请参阅图 1.1。

实现

步骤 1

在 Visual Studio 2010 中,打开我们在上一部分创建的解决方案。右键单击工作流(RecruitmentWorkflow)文件夹,然后单击“添加”->“新项”。从 SharePoint 2010 节点中选择“模块”。我们将它命名为“Forms”。现在右键单击新创建的模块并添加现有项。浏览我们创建的 InfoPath 窗体,并将其添加到 Forms 模块中。如果观察 Forms 模块中的 Elements.xml 文件,Visual Studio 已在模块下添加了一个新的节点,对应于新添加的 InfoPath 窗体。

图 1.2

在主功能清单文件(Feature1.Template.xml)中,参考图 1.2,如果缺少以下节点,请在 property 节点内添加它们。

<Property Key="GloballyAvailable" Value="true"/>
<Property Key="RegisterForms" Value="Forms\*.xsn"/>

第二步

我们需要配置工作流的 Elements.xml 文件,添加 InfoPath 窗体的 URN、关联数据等详细信息。在此之前,我们需要更改 InfoPath 窗体并发布我们的 InfoPath 窗体。

要配置设置,请在“文件”菜单中选择“Info”选项卡。在“窗体信息”面板中,选择“高级窗体选项”。在“安全性和信任”选项卡中,取消选中“自动确定安全级别”复选框,然后选择“域”单选按钮。单击“确定”并关闭窗体。

要发布 InfoPath 窗体,请在“文件”菜单的“发布”选项卡中,单击“网络位置”按钮。浏览文件系统上的路径,然后单击“下一步”按钮。在向导的下一个窗口中,清除文本框(非常重要,因为如果此文本框不为空,SharePoint 将无法识别已发布的窗体,因此它不会呈现窗体)。这将弹出一个警告消息;单击“确定”并继续。通过单击“发布”按钮完成发布过程。

要查找 InfoPath 窗体的 URN,请转到已发布 InfoPath 窗体的“文件”菜单(确保它是已发布的 InfoPath 窗体),在右侧的面板中,单击“窗体模板属性”按钮。这将打开一个弹出窗口,该窗口中的“ID”字段是 InfoPath 窗体的 URN。

Elements.xml 文件中,我们需要将 TaskListContentTypeId 设置为以下值

TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93160"

此内容类型包含在 Microsoft SharePoint Server 2010 中,它指定自定义任务显示和编辑窗体,这些窗体包含用于呈现 InfoPath 窗体的 Office Forms Server 控件。

接下来,将一个元素添加到工作流模板定义的 Metadata 元素中。此元素的形式为 <TaskN_FormURN>URN Value</TaskN_FormURN>,其中 N 表示我们在工作流中为此任务类型分配的整数值,URN Value 是我们从 InfoPath 窗体获取的 URN 字符串。

此外,我们还需要将关联数据添加到我们的元素文件中。我们将向工作流传递虚拟数据,因为在关联期间没有数据需要传递给工作流。在 Elements.xml 中的 Categories 节点之后添加以下代码。配置后,请参阅图 1.3 查看 Elements.xml

<AssociationData>
              <Data></Data>
</AssociationData>

图 1.3

步骤 3

如果您精通 InfoPath 2010,您可以在同一个窗体中为我们工作流中的各种任务创建视图。或者,您可以为每个任务创建一个新窗体,并以类似的方式将其添加到解决方案中。添加新窗体只会更改 Elements.xml 文件中的 MetaData 元素(需要为新 InfoPath 窗体添加额外的 URN)。

我们在示例中为任务创建了不同的窗体。下一个任务(如果初步审核被批准)将是技术审核任务。现在,我们希望在技术审核任务中显示初步审核的评论,以便技术小组可以获得有关候选人的额外信息。

要实现这一点,我们必须能够将信息从工作流发送到 InfoPath 窗体。这可以通过 InfoPath 中的数据连接来完成。我们需要创建一个名为“ItemMetadata.xml”的 XML 文件,其中包含我们希望在 InfoPath 中提供的字段名称。然后,我们在 InfoPath 中创建一个新的数据连接来接收数据。ItemMetaData.xml 中列的名称应以“ows_”开头。您可以使用单个 ItemMetaData.xml 文件将多个值传递给 InfoPath 窗体。参考图 1.4。

图 1.4

要将此 XML 文件添加到 InfoPath 窗体,请在 InfoPath Designer 中,选择“数据”选项卡,然后单击“数据连接”按钮添加新的数据连接。在弹出窗口中,单击“添加”按钮,在下一个窗口中选择“接收数据”,然后单击“下一步”按钮。在下一个窗口中选择“XML 文档”选项,浏览 XML 文件,单击“下一步”,然后使用选定的默认值完成配置。

在“字段浏览器”窗口中,下拉列表现在显示两个连接。您可以选择将字段从新配置的数据连接拖放到 InfoPath 窗体上。参考图 1.5。

图 1.5

步骤 4

在 Visual Studio 中,当创建任务时,将调用初步审核状态中“创建任务”活动的 MethodInvoking 事件。我们在该事件中指定任务的详细信息。为了将任务与特定的 InfoPath 窗体相关联,我们需要配置此任务的 TaskProperties 字段的 TaskType 属性。在我们的示例中,我们将有以下代码。这里,我们将 TaskType 与我们在 Elements.xml 中输入时关联的任务编号对应起来。

//Task Type corresponds to TaskURN specified in Elements.xml
this.createTaskInitialClearanceTaskProperties.TaskType = 1;

请确保 Elements.xml 中指定的 URN 与代码隐藏文件中的任务相匹配;否则,在打开任务窗体时,工作流将遇到错误。

要将数据从 SharePoint 发送到 InfoPath 窗体,我们在 InfoPath 窗体中设置了一个接收数据连接。我们可以通过在同一事件(即 MethodInvoking 事件)中设置任务属性字段的 ExtendedProperties 来实现此目的。ExtendedProperties 是一个哈希表(键值对),在本例中,键将是我们使用的字段名称 ItemMetaData.xml,值将是上一阶段评论的值。

当用户执行任务后,将调用 EventDriven 活动的 Invoked 事件。任务完成后,我们需要访问用户在 InfoPath 任务窗体中输入的值。我们可以通过使用此任务的 AfterProperties 字段的 ExtendedProperties 属性来访问这些值。以下是与技术审核任务相关的所有事件和方法的代码片段。

这是 MethodInvoking 事件

private void createTaskTechnicalClearance_MethodInvoking(object sender, EventArgs e)
{
    try
    {
        //Create a new TaskId for the Task
        this.createTaskTechnicalClearanceTaskId = Guid.NewGuid();

        //TaskProperties field is used to configure the Task Details.
        this.createTaskTechnicalClearanceTaskProperties.Title = "Technical Clearance";

        //You can assign a Task to an user or to a group.
        //Here we assign the task to HR-Group

        SPListItem listItem = this.workflowProperties.Item;
        //Write the remarks value to the list item
        if (listItem != null)
        {
            //Check if TechnicalInterviewAssignedTo Field has
            //a value, and Assign this Task to the value of this Field
            if (listItem.Fields.ContainsField("TechnicalInterviewAssignedTo"))
            {
                this.createTaskTechnicalClearanceTaskProperties.AssignedTo = 
                   listItem["TechnicalInterviewAssignedTo"].ToString();
            }

            //To send InitialRemarks to the InfoPath Form,
            //we add it to the ExtendedProperty of the TaskProperties
            //ExtendedProperties is a hashtable (Key-Value pair). 
            //The Key will be the name of field we have used
            //in ItemMetaData.xml and Value will be the value of remarks
            if (listItem.Fields.ContainsField("InitialRemarks"))
            {
                if (this.createTaskTechnicalClearanceTaskProperties.
                     ExtendedProperties.ContainsKey("InitialComments"))
                {
                    this.createTaskTechnicalClearanceTaskProperties.
                      ExtendedProperties["InitialComments"] = 
                      listItem["InitialRemarks"].ToString();
                }
                else
                {
                    this.createTaskTechnicalClearanceTaskProperties.
                      ExtendedProperties.Add("InitialComments", 
                      listItem["InitialRemarks"].ToString());
                }
            }
        }

        //Task Type corresponds to TaskURN specified in Elements.xml
        this.createTaskTechnicalClearanceTaskProperties.TaskType = 2;

        this.createTaskTechnicalClearanceTaskProperties.DueDate = 
                       DateTime.Today.AddDays(2.0);
    }
    catch (Exception ex)
    {
        //throw ex;
    }
}

Invoked 事件

private void onTaskChangedTechnicalClearance_Invoked(
        object sender, ExternalDataEventArgs e)
{
    try
    {
        this.onTaskChangedTechnicalClearanceAfterProperties = 
           this.onTaskChangedTechnicalClearance.AfterProperties;
        this.onTaskChangedTechnicalClearanceBeforeProperties = 
           this.onTaskChangedTechnicalClearance.BeforeProperties;

        //Set the PercentComplete property to 1.0 (i.e. 100%)
        //to indicate that the task has been completed.
        this.onTaskChangedTechnicalClearanceAfterProperties.PercentComplete = (float)1.0;

        //Get the value of Remarks Column (InfoPath Form)
        //by using the ExtendedProperties property
        string remarks = this.onTaskChangedTechnicalClearance
                 BeforeProperties.ExtendedProperties["Remarks"].ToString();

        SPListItem listItem = this.workflowProperties.Item;

        //Write the remarks value to the list item
        if (listItem != null && 
             listItem.Fields.ContainsField("TechnicalInterviewRemarks"))
        {
            listItem["TechnicalInterviewRemarks"] = remarks;
        }
    }
    catch (Exception ex)
    {
        //throw ex;
    }
}

条件处理 - TechnicalClearanceApprovalProcess

private void TechnicalClearanceApprovalProcess(object sender, ConditionalEventArgs e)
{
    try
    {
        if (this.onTaskChangedTechnicalClearanceAfterProperties.PercentComplete == 
           (float)1.0 && this.onTaskChangedTechnicalClearanceAfterProperties.
                         ExtendedProperties["Status"].ToString().Contains("Approved"))
        {
            e.Result = true;
        }
        else
        {
            e.Result = false;
        }
    }
    catch (Exception ex)
    {
        //throw ex;
    }
}

就是这样!

历史

  • 2012 年 1 月 19 日:更新了源代码。
© . All rights reserved.