一步一步学习sharepoint2010 workflow 系列第三部分:自定义SharePoint代码工作流 第9章 Visual Studio工作流表单(Forms in Visual Studio workflows)

本章涵盖
■添加.NET代码到InfoPath表单
■编程方式检索表单数据
■在工作流中使用InfoPath和ASP.NET窗体

 

本章涉及运行在工作流内部的表单包含关联,启动和修改表单。 

初始化表单直接在工作流开始前收集信息。关联和修改表单,用户输入信息到工作流。两者区别是关联表单是当工作流添加到列表,库或者站点后,展现给用户,修改表单是在工作流执行时展现给用户。 

初始化表单在当工作流开始前需要从用户收集数据时派上用场,像Expense report。当你初始化一个工作流,你可能不知道谁需要去审批Expense report。初始化表单能捕捉从提交者得到他们的经理,然后工作流能确保适当的人去审批请求。 

 关联表单在Expense reports也是有用的。不需要每次上传Expense report都需要员工指定他们的经理,你可以使用关联表单员工只需输入一次,当自定义工作流首次添加到库时。

修改表单的使用,你可以改变工作流开始后的行为而其他两个表单是在工作流开始之前展示的。这里有一个工作流修改的例子。工作流分配一个任务,分配者想重新分配任务给某人。修改表单显示通过工作流状态页面的链接。链接只有你启用修改才会显示。修改开始后用户点击状态页面上的修改链接,他们将重定向到修改表单,进行输入信息。之后表单提交,修改将执行。 

你使用的表单是由你的工作流需求决定的,你将需要考虑实施方法。三种表单类型可以建在InfoPath或者ASP.NET。 

 每种表单的每种工具实施步骤在这种都是重点。此外,这章还介绍如何添加.NET代码到InfoPath表单,并且如何以编程的方法检索数据。你将通过一些例子去添加自定义表单到工作流通过SPD和Visual Studio。对于Visual Studio工作流,我们期待InfoPath表单和ASP.NET工作流表单.

 9.1 添加.NET代码到InfoPath表单( Adding .NET code to an InfoPath form)

在节7.5,你设置Expense report表单上两个新数据,并且映射到列。一个数据时expense type,另一个是total amount。目前,总金额字段不会自动计算。要计算这个数字,你需要添加代码去总计费用。你要代码能够每当有人更新金额字段都进行统计。该代码将通过循环所有的Amount字段并计算总额。这是一个通用例子,但是有.NET代码在表单中往往就能派上用场。 

在添加代码之前,你需要确保你安装了Visual Studio Tools for Application。如果你没有安装,你可以重新运行Office2010安装,选择添加新功能。在InfoPath文件夹下,选择Visual Studio Tools for Applications,然后从你的电脑运行(图9.1)。点击继续。将安装到你的计算机上。 

 图9.1

 

 随着Visual Studio准备完毕,现在是添加代码将去执行当Amount字段改变的时候。首先打开你的InfoPath表单。建立Expense Report表单在第7章,导航到Expense Reports库的库设置,到高级设置,点击编辑表单模板。这时会打开InfoPath,点击Amount字段。然后在Ribbon上有开发选项卡,点击更新事件按钮牛。这将打开Visual Studio并有一个新的项目,表单代码会自动生成(图9.2)。项目里面,你将发现一个代码文件标题是FormCode.CS。在此代码中有两个方法,InternalStartup和Amount_Changed。因为你选择的是Amount字段更改事件响应,你将看到InteralStartUp方法里有一个注册事件代码。的那个发生更改,它将调用Amount_Changed方法。

 图9.2

 当.NET代码在InfoPath表单中工作,它能帮助去了解上下文的事情,Infopath表单和它的代码链接一起,因此你需要去建立项目,并重新发布代码改变的InfoPath到SharePoint。另外一个功能使你有期望的调试经验可以用。按下F5,InfoPath客户端将呈现表单。如果你设置断点,你可以一步步通过你的代码。请记住,当调试,你是没有Web上下文的,因此,如果你想试着运行代码的基础是谁运行它,单元测试和调试将复杂点。

设置你喜欢的编程语言  

默认情况下,所有新的Visual Studio项目创建的InfoPath设置使用Visual Basic为程序语言。这可以很容易设置使用C#替代。在Ribbon上的开发选项卡,第一个按钮是语言。语言提供表单模板代码语言下拉列表框,你可以进行更新。如果下拉列表被禁用,是因为你已经创建了项目,所以不能改变。如果你不担心失去代码,单击“删除”按钮,然后你可以更新语言,并开始建立一个新的项目。

 接下来,你需要添加代码到方法,获取表单上的所有的expenses,并计算总金额,像清单9.1.拷贝请打并替换你的Amount_Changed方法。

Listing 9.1 Amount Changed Event Handler code 

 

XPathNavigator formData = this.CreateNavigator();

XPathNavigator expenseGroup = formData
.SelectSingleNode("/my:SPWFiAExpenseReport/my:Expenses",NamespaceManager);
XPathNodeIterator expenses = expenseGroup.SelectDescendants(
"Expense",
expenseGroup.NamespaceURI,
false);
double total = 0;
foreach (XPathNavigator expense in expenses)
{
string value = expense.SelectSingleNode(
"my:Amount", NamespaceManager).Value;
double amount = double.Parse(value);
total += amount;
}
formData.SelectSingleNode(
"/my:SPWFiAExpenseReport/my:TotalAmount", NamespaceManager)

.SetValue(total.ToString());

 

  代码中第一件事情是XPathNavigator创建,以帮助你挖掘在XML数据周围包含的所有输入到表单的值。你然后只从表单中选择Expenses数据。要做到这点,你调用SelectSingleNode 方法从formData上,这里需要XML路径。重要的是当你创建你的表单在Infopath中,确保给的字段描述是有意义的名称。XML结构直接映射到字段名称在路径中能够看到,用指定的SelectSingleNode方法。

现在你有了你的Expenses(重复表格数据),你需要一个集合对象才可以遍历每个Expense。为了得到这个集合,你调用SelectDescendants在expenseGroup对象,然后传递元素名称,在这里是Expense节点。接下来,你遍历每个Expense,并拉出每个Expense。然后添加到total,之后将总金额保存到TotalAmount域中。

如果你得到错误,当你发布的时候,检查Expense Report库中的TotalAmount字段数据类型。它应该是Double类型,不是文本(默认的)。
现在,你的代码完整,你应该确保它如预期的工作。生成改项目以确保没有错误。如果没有的话,按下F5启动调试器。单元测试expense report表单 并确保它的正确的计算总开支,保存数据到TotalAmount字段。当它运行正常,发布到SharePoint。

 沙盒解决方案必须启用

当你发布,你可能获得错误说沙盒解决方案没有启用(图9.3)。去启用沙盒解决方案,导航到你的服务器管理中心站点。点击系统设置,然后点击管理服务器上的服务,确保Microsoft SharePoint Foundation 沙盒代码服务是启动的。

  9.3

 

  沙盒解决方案与管理员-审批模板

在发布向导的一个步骤是发布为管理员审批模板。如果你选择表单库或者内容类型和你的表单有.NET代码在里面,默认情况下代码运行在一个叫沙盒的解决方案中。沙盒解决方案是一个新的概念。在SharePoint2007,所有启用浏览表单模板需要双传到表单服务通过SharePoint管理中心。在2010中一个站点集管理员能上传他们的表单模板到站点集自己的解决方案库。一个表单部署到沙盒明显只有在网站集,无论管理员审批模板(管理中心)是整个Farm可用。此外管理员审批模板能设置成充分信任,因此表单上的代码能做一些事情如跨域(获取和设置数据在某一个SharePoint Farm),和使用一些像SQL数据。

 


9.2编程方式检索表单数据(Programmatically retrieving form data from within a workflow)

  在最后一节,你看到如何以编程方式从表单上内置代码读数据。当一个外部系统发生什么,像工作流,需要交互数据?一个常见业务需求是有一个工作流当提交表单后响应,然后改工作流检索数据存储在表单。它处理数据之后,它能做一些事情,类似将数据放在业务应用程序的某些行或者外部处理或者发送邮件通知。

为了满足业务需求,你首先创建一个.NET代理类为Infopath表单从表单架构定义文件。这个类将是强类型,因此它将很容易对代码数据因为你将有智能感知在表单的字段和他们的值。如果你记得,这不同于代码后置的表单的工作,你需要充分利用XPath.毫无疑问你会喜欢这个代理方法,因为代码将更清洁,更容易理解。你可以使用这个代理类读取和写数据进出表单。注意当用户是编辑表单这个是不能用的。代理类能在用户交互前后利用,而XPath必须使用在交互期间。

让我们使用Visual studio建立一个顺序工作流叫ExpenseReportWorkflow。这个工作流将在表单的每次新开始报告输入到系统时触发。你将添加你的代理类到这个新的工作流项目,工作流将有一个通用Code活动将使用带来拉出表单数据。按照表9.1的步骤设置顺序工作流项目。 

 表9.1

 

 

 图9.4

 

现在你已经开始了工作流项目,你需要去生成一个代理类从你的InfoPath Expense Report模板。去生成代理类,你要去运行一个XSD命令从Visual Studio工具命令提示行,然后你将在命令行上获取到你的模板XML架构定义文件。每个Infopath表单是一个.CAb文件保存所有这些子文件,点击导出源文件按钮在InfoPath的文件菜单下面的发布选项卡。浏览你的硬盘驱动器目录。图9.5显示导出的7个文件。 

  9.5

 

  这个感兴趣的文件是myschema.xsd,包含你的表单XML架构。这个schema文件在产生代理类将指示XSD命令去哪里获得类,属性和字段。将为每个域字段创建类。例如你的代理文件将包含3个类:一个是根,一个叫Expenses(Expense集合),另外一个叫Expense(单个数据)。按照表9.2步骤生成代理类。

  表9.2

 

 

 

  现在代理类添加到Visual Studio项目中,让示例开始接受数据工作。列表9.2包含为更新code活动方法。右击RetrieveFormData Code活动然后选择 代码视图。使用列表9.2替换自动生成的RetrieveFormData_ExecuteCode方法,添加两个引用控件为System.Xml和System.Xml.Serialization.

 

list 9.2 通过强类型代理类检索数据                                                                                                                                                                                        

 1 private void RetrieveFormData_ExecuteCode(object sender, EventArgs e)

 

 2 {
 3 SPFile file = onWorkflowActivated1.WorkflowProperties.Item.File;
 4 XmlTextReader reader = new XmlTextReader(file.OpenBinaryStream());
 5 XmlSerializer serializer = new XmlSerializer(
 6 typeof(SPWFiAExpenseReport));
 7 SPWFiAExpenseReport fields = (SPWFiAExpenseReport)serializer
 8 .Deserialize(reader);
 9 double total = 0;
10 foreach (Expense expense in fields.Expenses)
11 {
12 total += expense.Amount;
13 }
14 file.Item["Total Again"] = total;
15 file.Item.Update();

16 }

 

 列表9.2开始时通过初始化SPFile对象。OnWorkflowActivated属性有一个表单列表项实例(SPListItem),列表项可以有附件。这个附件是表单库必须的。SPListItem的文件属性包含SPFile对象(附件),这也恰好有你的InfoPath表单 XML数据文件。

 然后你在SPFile对象上打开一个二进制流,并且加载到一个XmlTextReader.伺候,你的代理类获取实例,被分配去反序列化为通过你的代理类型。你的代理类对象包含所有属性和你的InfoPath表单的数据集合。这些数据是从表单字段映射过来的。

正如你的代码后置例子,你会遍历所有的expense,然后计算所有的expense amount 字段的值。在code-behind例子中,你要将值重新分配到列表项的列中,不过这次的列叫Total Again。这是第二种可行办法,但是它通常不是首选因为另一种方法不需要自定义代码。它演示代理的概念很好的。 

最后的事情是生成,部署并单元测试你的工作流。生成项目并确认他们没有错误。如果没有的话,部署项目通过右击项目名字,然后选择部署。这将你的工作流打包并部署到你指定的列表。 

现在无论创建一个新的Expense report或者编辑以存在的。你启动你的自定义工作流之前,创建一个新列标题叫Total Again因为你的代码将写入这个列。之后这个列将被添加,开始自定义expense report工作流部署(图9.6)

 图9.6

 

  工作流应该很快完成。注意一个新列叫Expense Report workflow被添加。然后Total Again列也被填充(图9.7)。code活动诚通实例化代理类到表单数据,并抓取和计算所有的expense amount。

  9.7

 

  9.3 Visual Studio工作流中的InfoPath表单(InfoPath forms in Visual Studio workflow)

 如前所述,你可以在Visual Studio工作流上建立ASP.NET或者InfoPath表单。这一节将介绍如何添加InfoPath表单到Visual Studio工作流。具体来说,本节将包含关联,启动和修改表单。示例你将要在一个工作流上管理支持需要一个网站集。如果你有成千上万个用户工作在一个网站集上,它可能是一个有帮助的工作流,可以帮助请求如帮助去添加或者配置一个WebPart或者设置一个文档库。工作流将管理帮助请求级别的支持。第一阶段可能是IT helpdesk,如果他们不能解决问题,能提高到站点集管理员。第三层能到技术架构师。
9.3.1 建立一个自定义关联表单(Building a custom association form)

  第一个InfoPath表单你想去添加的是一个关联表单去捕获每一层支持人员。当支持工作流添加到一个列表,这个表单提示用户去指定SharePoint组包含谁负责每一级支持。

本节项目的目的是使用关联表单和部署工作流。在后面的章节,你将知道如何使用启动和修改表单。目前,让我们从这个关联表单开始。图9.8显示这个表单看起来的样子。 

 图9.8

 

这个例子的前提条件 

所有例子通过本章的都是建立在一个问题列表上。创建一个新的问题列表叫Support Requests,然后使用一个空白表单模板创建表单本身,像图9.8

 图9.8

 重要的是注意如何配置这个表单上的提交按钮。配置并不复杂,但涉及提交按钮的几个步骤。按照表9.3的步骤来配置InfoPath表单“提交”按钮。

表9.3

 

 

 

 图9.9

  Infopath部署注意事项

当为Visual Studio工作流创建你的Infopath表单时,有两个地方需要注意。首先确认表单安全级别,当你发布时至少是域。如果你有设置它为自动检测级别,它可能已经被设置为域。你可以在表单选项下安全和信任设置它。域是需要和SharePoint数据交互的。完全信任将能访问你的个人电脑硬盘驱动器。 第二,你添加到Visual Studio工作流中的表单需要是发布版本的表单。在你添加到Visual Studio项目之前,确认发布过。你将使用到发布到网络地址功能。当你发布到网络地址,确保保持访问路径空白。你的工作流将知道从服务器访问表单的URL,但是将不会知道你指定一个网络路径或者URL的地址。

 现在你有固定的InfoPath表单,让我们创建一个新的Visual Studio顺序工作流为你的支持流程。在Visual Studio2010中创建一个顺序工作流。项目的名字叫SiteCollectionSupportWorkflow,工作流叫Site Collection Support workflow。你将被提示是创建一个列表工作流还是站点工作流。保持类型设置为列表工作流因为你想去绑定你的工作流到一个包含你的支持请求的列表。在向导的最后一个屏幕,取消选中复选框问你是否绑定工作流到列表。你想去绑定自身去测试关联表单。从本质上讲,如果你保持复选框选中,你需要关联工作流,之后你就看不到你的关联表单了. 

当你一个新的Visual Studio工作流项目创建,feature定义是自动创建的为这个工作流的部署。你需要去获取你的InfoPath表单到这个feature定义,并指示工作流去使用这个表单而不是使用空白表单。第一步是去添加InfoPath表单到工作流。然后,你可以设置它的部署类型属性为ElementFile。之后表单被设置为ElementFile,feature定义将自动知道去导入它到feature中。按照表9.4的步骤去添加表单到feature。 

表9.4

 

 

  随着你的feature定义适当的包装你的表单,你现在需要去指示你的feature去部署它到表单服务器。InfoPath关联表单(以及启动和修改表单)必须部署全局(globally)在表单服务器进行工作。此时,你也许奇怪为什么你无法手工上传表单到表单服务器,而是通过管理中心。这个麻烦是因为手工上传表单没有工作流启用,你的表单明显需要启用工作流。要启用表单,你需要feature去部署表单到表单服务器通过一个事件处理。按照表9.5的步骤去设置这个事件处理。

  表9.5

 

 

 图9.10

 

此过程中的最后一步是去指示工作流去使用你自定义关联表单当工作流首次添加到列表。这个完成需要通过修改工作流的Elements.xml文件。这里有两个主要的事情你要去配置XML文件:AssociationUrl 工作流属性和一个元数据叫Association_FormURN. AssociationUrl 属性是设置SharePoint的ASPX页面布局。这个ASPX页面有Infopath Form Viewer的WebPart可以呈现你的InfoPath表单。WebPart获取Association_FormURN元数据以找出什么呈现在表单服务器上。你将需要固定你的表单URN到这个meta属性。按照表9.6的步骤去配置这个Elements.xml文件。

 表9.6

   

 

List 9.3 工作流的Elements.xml添加 association form 之后                                                                                                        

 

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Workflow
Name="Site Collection Support Workflow"
Description="My SharePoint Workflow"
Id="719253c3-78d7-41b3-a0a8-bfa228b8588a"
CodeBesideClass="SiteCollectionSupportWorkflow.Workflow1.Workflow1"
CodeBesideAssembly="$assemblyname$"
AssociationUrl="_layouts/CstWrkflIP.aspx">
<Categories/>
<MetaData>
<Association_FormURN>urn:schemas-microsoftcom:
office:infopath:SupportGroupAssocationForm:-
myXSD-2009-12- 12T17-59-13
</Association_FormURN>
<AssociationCategories>List</AssociationCategories>
<StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
</MetaData>
</Workflow>

</Elements>

 

  让我们测试你的工作流和自定义关联表单。再次生成和部署项目去增加你的更新。然后,找到一个SharePoint列表并添加你的Site Collection Support workflow。你将注意到,当你添加工作流到列表,你的关联表单加载去提供用户选项为群体描述每一层的支持(图9.11)。

 图9.11

 

9.3.2 建立一个自定义启动表单(Building a custom initiation form)

 启动表单添加到Visual Studio工作流大部分和关联表单的添加是相同的。上一节我们走过关联表单的过程。因为关联表单和启动表单是相似的,我们不打算翻版同样的流程。相反,你将学习如何在上一节所设定的项目中添加启动表单。按照表9.7开始前创建InfoPath启动表单(图9.12)

 图9.12

 

表9.7

 

 

自动启动工作流将不显示启动表单  

如果你的工作流是设置自动启动当一个新项被添加,当新项添加启动表单不会被加载。启动表单将只显示在手动启动的工作流上。

9.3.3 关联表单或者启动表单工作数据( Working with the association or initiation form data)
 

  现在你的关联和启动表单继承到一个自定义工作流,工作流如何去做这些表单的数据?重要的是知道如何在工作流中检索表单数据。从本质上讲,OnWorkflowActivated活动有个属性叫WorkflowProperties.在WorkflowProperties属性,有两个属性存储你的关联和启动数据,AssociationData和InitiationData。这些属性是字符串包含你的表单XML数据。你获取字符串到一个.NET类,它是从表单架构定义文件中建立的。回到关联表单,建立一个代理类从表单架构,从工作流获取AssociationData,并获取字符串。按照表9.8的步骤做这件事。

 表9.8

 

 

列表9.4 反序列化你的关联表单数据到一个对象                                                                                                                            

 

XmlSerializer serializer = new XmlSerializer(typeof(SupportGroups));

XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(
onWorkflowActivated1.WorkflowProperties.AssociationData));
SupportGroups associationFormData =
(SupportGroups)serializer.Deserialize(reader);
string tier1 = associationFormData.Tier1Group;
string tier2 = associationFormData.Tier2Group;
string tier3 = associationFormData.Tier3Groupstring currentTier = tier1;

 

首先,列表9.4创建一个XmlSerializer 从你的代理类。在这个例子中使用的是SupportGroups类是建立关联表单架构定义文件。接下来,你读取用户输入到关联表单的数据到XmlTextReader对象。这个XmlTextReader对象将保持数据用户输入数据格式和关联表单架构定义一致。之后你有了这个XML,你可以转换它到代理类的新对象上。这个对象,你可以开始对输入到表单的数据进行获取。

这个动作讨论了启动和关联表单。请记住这两个表单类型总是出现在用户工作流开始之前。现在的时间去讨论,工作流开始后,修改表单。 

 

9.3.4 配置活动为工作流修改(Configuring activities for workflow modifications )

  工作流的修改给你的最终用户在工作流启动后改变他们工作流行为的能力。这就是通常当某人想要重新分配一个任务。本节将扩展Support workflow,让他们可以修改工作流并指定不同SharePoint用户组去负责完成的支持请求。

在你建立和部署修改表单之前,你需要告诉你的工作流允许修改。一个修改连接显示在工作流状态页面上。当一个用户点击这个连接,他们被带去修改表单,之后提交表单,你的工作流可以与用户提交的输入的数据做出反应。关键是要在工作流状态页面上获得此连接因为它默认是不存在的。你必须明确的允许修改。图9.13显示这个连接在工作流状态页面上。注意这个连接使用可配置文本。 

 图9.13

 

有两个主要工作流修改活动使用去启用这个功能,EnableWorkflowModification 和OnWorkflowModified。你可以使用EnableWorkflowModification 活动去启用修改,以便显示链接在工作流状态页面上。当用户点击这个链接,他们带到修改表单,当这个表单提交,工作流框架触发workflowModified事件,OnWorkflowModified活动作出反应。 

 如前所述,你可以指定工作流能不能修改。通常情况,EnableWorkflowModification活动是部署在一个EventHandlingScope活动。你可以使用EventHandlingScope 活动去管理当一个修改发生。在工作流执行内部的 EventHandlingScope活动,EnableWorkflowModification活动也同样在里面,修改将被启用。只要工作流传递出EventHandlingScope活动,修改将不再可用。

注意图9.14 EventHandlingScope 活动有多个视图。OnWorkflowModifed 活动是放置在事件处理视图,并可以与在EventHandlingScope活动范围中的参与工作流修改 .

 图9.14

 

 

你可以切换视图通过右击活动,然后选择你想要的编辑的视图。在视图中你能删除活动。注意除了通用事件处理做出反应,你可以对异常做出反应。现在去配置这些活动。按照这些步骤去添加功能到你的support工作流。

 表9.9

 

 

现在你添加业务逻辑到这个工作流使其真实。让我们添加一个While loop活动和一个OnWorkflowChanged活动去等待support request完成。如果请求完成,工作流执行完毕。按照表9.10去配置while和OnWorkflowChanged活动,工作流将使用去等待请求完成。 

 表9.10

 

 

Listing 9.5 WhileRequestIsNotComplete 方法                                                         

 

string status = onWorkflowActivated1.WorkflowProperties.
Item["Status"].ToString();
if (status == "Resolved")
e.Result = false;
else

e.Result = true;

 

 

该代码收件检索状态列的值,如果请求是resolved,循环停止,工作流完成。如果请求是 not Complete,循环继续,等待completed。这段代码输入之后,你完成了EventHandlingScope活动。图9.15显示你的工作流的样子。

 图9.15

 

当一切看起来都搞定了,现在去配置修改事件处理和设置OnWorkflowModified活动。要做到这点,添加EventDriven活动到EventHandlingScope活动事件处理视图。在你的OnWorkflowModifed活动里面的EventDriven活动,每次工作流在此范围内修改,这个活动都会触发。按照表9.11去配置这些步骤。 

 

 

  表9.11

 

 

 图9.16

 

 9.3.5 建立一个自定义修改表单(Building a custom modification form)

现在你有了修改-启用工作流的基础,现在去添加你的修改表单去进行混合。一个InfoPath修改表单是一个对话框上。在高级别,按照以下步骤去整合InfoPath修改表单。

1 创建表单  

2 设置工作流的Context data,表单使用去进行沟通。
3 编辑工作流 elements.xml文件去告诉工作流哪个表单被使用。

让我们开始第一个步骤,去设置表单本身。 InfoPath表单你将被使用在本节将去扩展你之前设置的Support request系统。 

你需要一个表单,用户可以使用去修改工作流,并且可以升级support request到下一个级别的support。 用户可以做这些如果他们不觉得不专业的回答请求的疑问或问题。图9.17显示示例表单将被使用。

 图9.17

 

   

 

  这个表单有两个数据块,当前支持级别和下一个支持级别。如果你还记得,你的工作流关联表单允许用户去指定SharePoint组包含谁负责每一层的支持。您希望修改表单让用户升级支持。你的工作流代码将通过这两个数据块,用户将确认他们想升级。如果他们这样做,你的工作流代码将重新分配通过列表项上的所有者列。

  你开始配置你的工作流的XML文件去告诉它使用这个表单之前,你需要设置你的上下文数据。如上所述,工作流能通过数据备份和通过EnableWorkflowModification和OnWorkflowModifed活动的ContextData属性传输数据。此时,这个属性是设置空字符串。它需要被设置为一个字符串,其中包含表单的XML架构定义以及任何你想传递的表单数据。有了这个设置,你的工作流将CurrentOwnerGroup和NExtTierGroup值传递到你的InfoPath表单。

  首先,实例化一个你的表单的XML架构定义的代理类。要活的此类,你需要去使用XSD命令。按照表9.12的步骤去加你的表单的代理类并添加代理类到你的Visual studio 项目。 

  表9.12

  

 

新的字段需求 

在列表9.6 在9.3.3节,你创建了四个字符串的字段在OnWorkflowActivated1_Invoked方法:tier1,tier2,tier3,和currentTier.这些字段是本地的字段。 列表9.6引用这些字段,使他们将现在需要去定义外部方法并在整个类可用。

  列表9.6 EnableWorkflowModification1_MethodInvoking

TicketModificationFields data = new TicketModificationFields();

data.CurrentOwnerGroup = currentTier;
data.NextTierGroup = tier2;
using (StringWriter writer = new StringWriter())
{
XmlSerializer s = new XmlSerializer(
typeof(TicketModificationFields));
s.Serialize(writer, data);
this.enableWorkflowModification1_ContextData1 = writer.ToString();

} 

 

首先,此代码实例化你的代理类。然后设置在这个类中将被传递到InfoPath表单的值。表单需要知道currentTier和NextTier。接下来,序列化这些数据到一个StringWriter对象,它可以设置字符串值到InfoPath modification 表单的ContextData属性中。 

 你以获得ContextData,你现在能专注于InfoPath旅程的最后一部分,怎样去告诉你的工作流哪个表单被使用当有modification链接被点击时。这些都需要在workflow的Elements.xml文件完成。你首先需要去获得你的表单到项目和feature。要做到这点,添加发布的表单到工作流。当加入后,设置表单的DeploymentType属性为ElementFile。之后,你的Visual Studio解决方案管理器看起来像图9.18.

  9.18

 

在你的modification表单,最终需要告诉工作流去使用它。按照表9.13去编辑Elements.xml文件 

表9.13

 

 

再次生成并部署项目。这将更新最后的Elements.xml。提醒,你需要使用一个开箱即用的问题列表名字叫SupportRequest去进行测试。 

注意Status列的依赖(Issue Status是显示名称)。添加工作流到列表,并指定一些值在关联表单。随后,创建一个新项在这个列表(设置Status为Active),并启动在项上的工作流。你启动它之后,工作流将进行等待Issue Status列设置为Resolved。同时,修改已启用。点击In Progress和将带你到工作流状态页面。点击Eacalate Support Request modification链接,你的表单将显示。之后你点击提交。OnWorkflowModifed活动将触发,因为当前没有代码在活动上,工作流将记录modification success(图9.19)到历史列表。 

 

  9.19

 

 

  9.4 Visual studio中的ASP.NET表单 (ASP.NET forms in Visual Studio workflows)

在我们讨论万InfoPath的关联和启动表单后,你将发现ASP.NET表单让你耳目一新。这是因为它更容易部署ASP.NET表单到Visual Studio 工作流。虽然ASP.NET表单开发需要技巧,但是他们更容易部署。部分原因是-你添加新的ASP.NET表单到工作流通过右击工作流,选择添加->新项,然后选择你想添加的表单类型。添加之后,表单将自动打包到feature,剩下就是部署项目了。然后当你关联你的工作流到一个列表或者在项上启动工作流,你将获得你的新的自定义ASP.NET表单!这仅仅需要几秒钟!不要高兴的太早,你将注意到当你看到你的表单在浏览器中,但是它是空白的。部署很容易;现在的时间是去开发控制你的表单并开始在工作流和表单之间传递数据。 

  你将在本节创建一个例子是一个通用的启动表单。因为关联和启动表单是几乎相同的方式创建的。在演练中,不同的关联表单将被调用,所以你要创建一个关联表单,本演练将会有帮助。

不是在上节的Support Request工作流上,让我们开始一个新的项目。创建一个新的顺序工作流叫TestASPNETWorkflowForms。创建一个列表工作流, 并绑定到一个你在向导上选择的列表。之后项目被创建,右击Workflow1,选择添加新项。“新项目”对话框将出现(图9.20)。选择添加一个关联或者启动表单。 

 图9.20

当你添加表单后,你将注意到你获得一个ASP.NET的HTML视图(图9.21)。这是自动生成的表单已经有一个按钮,并准备就绪。如果你要到表单的code_behind(右击表单并选择代码视图)你将注意到四个自定生成的方法。首先是Page_Load方法。你可以使用这个方法去设置默认值为你的表单字段。第二个是GetInitiationData(或者GetAssociationData)方法。你的工作流调用此方法去检索用户输入到表单的值。在此方法,你仅仅需要去返回一个字符串包含一个序列化的类存储数据。然后,工作流获取到,你可以反序列化这个类对象,工作流可以对这些数据做一些事情。第三个和第四个方法是提交或者取消表单。 

  9.21

 

  有些小担心这些因为他们已经为你填充。通常你甚至不需要改变这些方法,但需要根据你希望或需要的的业务逻辑。

回到你的ASP.NET HTML视图,你添加ASP.NET控件到这个表单上为了你的用户交互。在PlaceHoldMain里面的占位符,添加一些文本框。你将使用这些文本框去允许用户添加信息。你将带着这些信息,传递给你的工作流。图9.21显示完成后的代码的样子。

现在你有了你想要的表单,你需要去用户输入数据并传入到工作流。要做到这点,你将返回一串字符串包含返回的数据通过GetInitiationData方法(或者GetAssociationData)。一定确认只有这串字符串,它表示一个序列化的表单,工作流可以实例化并且可以序列化和反序列化。右击Workflow1,选择添加->新项。选择一个类文件,并设置名字为InitiationFormParameters.设置类为Public,有两个Public的字符串,在启动表单内。 

public class InitiationFormParameters

{
public string InitiationParameter1;
public string InitiationParameter2;

} 

 

回到ASP.NET表单的Code-behind,找到GetInitiationData方法,添加列表9.7的代码到这个方法,并添加两个Using块分别为System.Xml和System.IO。

列表9.7 GetInitiationData 方法 
string initdata = string.Empty;

InitiationFormParameters data = new InitiationFormParameters();
data.InitiationParameter1 = InitParameter1.Text;
data.InitiationParameter2 = InitParameter2.Text;
using (StringWriter writer = new StringWriter())
{
XmlSerializer s = new XmlSerializer(
typeof(InitiationFormParameters));
s.Serialize(writer, data);
initdata = writer.ToString();
}
return initdata;

 

 

这个代码首先创建一个你的类的实例,并指定其属性去存储表单的值。之后你序列化这个类到一个字符串,然后返回序列化的数据。 

你的工作流调用这个GetInitiationData方法,并加载字符串到OnWorkflowActivated活动的一个属性叫InitializationData(或者AssociationData)。在OnWorkflowActivity活动的事件处理中,你可以反序列化这个InitializationData属性存储的字符串到一个类对象,你的工作流能使用。要做到这点。在工作流设计界面,右击OnWorkflowActivated活动,选择生成处理。替换列表9.8的代码到OnWorkflowActivated—_InVoked方法。此外,添加System.Xml.Serialization和System.Xml两个using块。

 

 

列表9.8  onWorkflowActivated1_Invoked 方法

 string param1;

string param2;
private void onWorkflowActivated1_Invoked(object sender,
ExternalDataEventArgs e)
{
XmlSerializer serializer = new
XmlSerializer(typeof(InitiationFormParameters));
XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(
onWorkflowActivated1.WorkflowProperties.InitiationData));
InitiationFormParameters initiationFormData =
(InitiationFormParameters)serializer.Deserialize(reader);
param1 = initiationFormData.InitiationParameter1;
param2 = initiationFormData.InitiationParameter2;
}

 

这段代码的目的是检索用户输入的数据在启动表单(或者关联表单)。你的工作流能对这些数据进行动作。首先的事情是你想去独处InitializationData属性(或者AssociationData)的数据到XmlTextReader。然后反序列化XML到一个新的对象,使用序列化的类去进行反序列化。有了你的对象后,你可以分配一些全局变量或者采取其他行动。 

  有了这些代码后,你需要做最后一步以确保工作。让我们添加LogToHistoryListActivity活动在OnWorkflowActivated活动下面。你可以使用历史记录去呈现在你的表单值在工作流状态页面上。在LogToHistoryListActivity活动添加好后,右击它,选择生成处理。在生成的方法里,添加下面的代码写入你的表单值:

logToHistoryListActivity1.HistoryDescription ="Param1: " + param1 + " Param2: " + param2;

完成记录活动后,你可以开始测试。生成项目并部署它。如果有还没相关的工作流列表,现在可以建立。另外,启动列表项上的工作流。当你启动工作流,你应该看到自定义ASP.NET 启动表单(图9.22)。  

 图9.22

之后你输入一些值并提交表单,你将看到Completed 状态。点击Status列,它将你带到工作流状态页面。在底部,你可以看到工作流历史,你输入到启动表单列表值将显示(图9.23)。

 图9.23

 

 

本人声明

 
  本博客内的文字和图片除标明出处和转贴的外,均系本人原创作品,如转载或使用,不是用于盈利目的,尽请使用,但请注明引自这里和作者的名字;有商业用途的,请与本人联系,协商后再作使用,否则我将采取法律手段维护自己的利益。谢谢合作。meiweijun@163.com

 

posted on 2011-10-08 16:40  梅卫军  阅读(2662)  评论(2编辑  收藏  举报