工作流模板的初始化表单
初始化表单是启动流程时调用的表单,供启动流程的用户填写一些数据。在流程代码中,可以通过workflowProperties字段的InitiationData属性获取到初始化表单的数据。InitiationData放置的是初始化的xml格式的数据。
若存在关联表单,初始化表单的数据源架构必须跟关联表单一致,关联表单的数据将作为初始化表单的默认值。为了保持架构一致,初始化表单可以直接将关联表单另存为一份副本进行修改。
下面给文档审批流程示例添加一个功能:当启动文档审批流程时,用户可以重新指定审批人,重新指定接受提醒邮件的人员。
1.设计表单模板
Step1 将AssociationForm.xsn另存为InitiationForm.xsn。
Step2 修改表单,如图1所示。
图1 InitiationForm表单样式
Step3 发布表单。确认表单的安全级别为"完全信息",将表单发布到项目所在目录,发布文件名为"InitiationForm.xsn"。
2.修改配置文件
接下来需要修改配置文件,将InitiationForm.xsn跟工作流模板进行关联。
Step1 修改feature.xml。在ElementManifests节点下添加如下代码。
<ElementFile Location="InitiationForm.xsn" />
Step2 修改workflow.xml文件。在Workflow节点下添加如下属性。
InstantiationUrl="_layouts/IniWrkflIP.aspx"
在MetaData节点下添加如下属性。
<Instantiation_FormURN>urn:schemas-microsoft-com:office:infopath:InitiationForm:
-myXSD-2008-10-04T07-45-17</Instantiation_FormURN>
FormURN可以通过infopath属性窗口获得。
3.修改工作流代码
修改工作流代码,从初始化表单数据中获取数据,进行分配任务和发送邮件操作。只需要将ConfigurationData属性的获取逻辑修改如下。
private ConfigurationData _ConfigurationData;
///<summary>
///配置数据
///</summary>
public ConfigurationData ConfigurationData
{
get
{
if (_ConfigurationData == null)
{ //将初始表单数据反序列化为相应的对象
XmlSerializer serializer = new XmlSerializer(typeof(
ConfigurationData));
XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(
this.workflowProperties.InitiationData));
_ConfigurationData = (ConfigurationData)serializer.Deserialize(
reader);
}
return _ConfigurationData;
}
}
因为初始化表单和关联表单的数据源架构一致,所以仍然可以直接把初始化表单数据直接反序列化为ConfigurationData类型。
复合任务活动和多步审批流程
每次创建任务都需要createTask、onTaskChanged和completeTask 3个活动配合来完成,这是一个很烦琐的过程,并且流程图的可视化效果也变差了。WF工作流框架中的活动支持复合,即多个单一的活动可以组合成一个活动,本节实现这样一个任务复合活动并用它来实现多步的文档审批流程。创建任务复合活动步骤如下。
Step1 新建一个活动,名称为"TaskActivity"。
Step2 拖曳createTask、onTaskChanged和completeTask 3个活动到设计器中。
Step3 拖曳一个code活动到设计器中,如图2所示。
图2 TaskActivity
Step4 设置createTask、onTaskChanged和completeTask的correlationToken属性为"taskToken"。
Step5 将createTask、onTaskChanged和CompleteTask的TaskId绑定到活动类的taskId字段,将createTask的SpecialPermission属性绑定到活动类的specialPermission字段。
Step6 将createTask的TaskProperties属性绑定到活动类的TaskProperties属性。TaskActivity的任务数据应该公开供外部调用,所以将TaskProperties声明为属性,而不是字段,如图3所示。
图3 绑定到活动类的TaskProperties属性
Step7 将onTaskChanged的BeforeProperties和AfterProperties属性均绑定到活动类的TaskProperties属性。
Step8 任务的操作人需要由外部代码来指定,TaskActivity需要提供一个事件,供外部代码处理,以便指定任务操作人。首先定义一个事件参数类。
///<summary>
///任务事件参数
///</summary>
public class TaskEventArgs : EventArgs
{
///<summary>
///任务属性
///</summary>
public readonly SPWorkflowTaskProperties TaskProperties;
public TaskEventArgs(SPWorkflowTaskProperties taskProperties)
{
TaskProperties = taskProperties;
}
}
在TaskActivity类中添加事件声明代码。
//任务创建前触发的事件
[DesignerSerializationVisibilityAttribute(
DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("杂项")]
public event EventHandler<EventArgs> TaskCreating;
Step9 处理createTask的MethodInvoking事件,代码如下。
private void createTask1_MethodInvoking(object sender, EventArgs e)
{
this.taskId = Guid.NewGuid();
if(this.TaskProperties == null ) //实例化TaskProperties
this.TaskProperties = new SPWorkflowTaskProperties ();
if (TaskCreating != null) //触发事件
TaskCreating(this, new TaskEventArgs(this.TaskProperties));
//设置任务编辑权限
if (!String.IsNullOrEmpty(this.TaskProperties.AssignedTo))
this.specialPermissions.Add(this.TaskProperties.AssignedTo,
SPRoleType.Contributor);
}
以上代码创建了任务ID,执行了TaskCreating方法,并将任务的操作权限赋给任务操作人。
Step10 在任务完成后,希望外部代码也会进行处理,所以在Step3中添加了一个code活动,用这个code活动来调用任务完成事件。在TaskActivity类中添加任务完成事件声明代码。
//任务完成后触发的事件
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.
Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("杂项")]
public event EventHandler<EventArgs> TaskCompleted;
处理code活动的ExecuteCode事件,代码如下。
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
if (TaskCompleted != null) //触发任务完成后事件
TaskCompleted(this, new TaskEventArgs(this.TaskProperties));
}
最终的TaskActivity活动设计界面如图4所示。
图4 TaskActivity
TaskActivity完成后,多步审批流程的设计就变得简单了。下面将文档审批流程示例修改为2级审批:第一级由用户1审批,若用户1审批通过则给第二级用户2审批;若用户1拒绝,则结束流程。操作步骤如下。
Step1 添加第一级审批。从左边工具栏上拖曳TaskActivity到工作流设计器中,处理TaskActivity的TaskCreating事件,代码如下。
///<summary>
///分配一级审批任务
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity1_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.AssignedTo = "codeart\\user1";
e.TaskProperties.TaskType = 0;
e.TaskProperties.Title = "第一级用户审批";
}
以上代码指定了第一级的审批人为user1。处理TaskActivity的TaskCompleted事件,代码如下。
public bool task1ApprovalResult = false;
public string task1Comments = "";
///<summary>
///一级审批任务完成后的处理
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity1_TaskCompleted(object sender, TaskEventArgs e)
{
//一级审批任务完成后,将是否通过信息记录到task1ApprovalResult变量中
task1ApprovalResult = Convert.ToBoolean(e.TaskProperties.
ExtendedProperties["approval"]);
task1Comments = ""+e.TaskProperties.ExtendedProperties["comments"];
}
以上代码将第一级审批的结果和审批意见分别记录到task1ApprovalResult和task1Comments两个全局私有变量。
Step2 添加第二级审批。先拖曳IfElse活动到工作流设计器中,设置ifElseBranchActivity1的类型为"Declarative Rule Condition",ConditionName为"task1Approved",Expression为:
this.task1ApprovalResult == True
设计器如图5所示。
图5 ifElseBranchActivity1的条件设置
拖曳TaskActivity到ifElseBranchActivity1内,处理TaskCreating事件,代码如下。
///<summary>
///分配二级审批任务
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity2_TaskCreating(object sender, TaskEventArgs e)
{
e.TaskProperties.AssignedTo = "codeart\\user2";
e.TaskProperties.TaskType = 0;
e.TaskProperties.Title = "二级用户审批";
}
以上代码指定了第二级的审批人为user2。处理TaskActivity的TaskCompleted事件,代码如下。
public bool task2ApprovalResult = false;
public string task2Comments ="" ;
///<summary>
///二级审批任务完成后的处理
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void taskActivity2_TaskCompleted(object sender, TaskEventArgs e)
{
//二级审批任务完成后,将是否通过信息记录到task2ApprovalResult变量中
task2ApprovalResult = Convert.ToBoolean(
e.TaskProperties.ExtendedProperties["approval"]);
string task2Comments = ""+e.TaskProperties.ExtendedProperties
["comments"];
string totalComments = "user1 审批意见:" + task1Comments + "\n user2
审批意见:" + task2ApprovalResult;
//更新内容审批状态
this.UpdateModerationStatus( task2ApprovalResult , totalComments ) ;
}
以上代码按照审批结果修改文档的内容审核状态,UpdateModerationStatus用来更新文档状态,代码如下。
///<summary>
///改变内容审批状态
///</summary>
///<param name="approval"></param>
///<param name="comments"></param>
private void UpdateModerationStatus(bool approval, string comments)
{
SPModerationStatusType approvalState = approval ? SPModerationStatusType.Approved : SPModerationStatusType.Denied;
SPListItem item = this.workflowProperties.Item;
item["_ModerationStatus"] = (int)approvalState; //修改审批状态字段
item["_ModerationComments"] = comments; //修改审批批注字段
item.Update();
}
Step3 若第一级审批未通过,则需要设置文档状态为"已拒绝"。拖曳code活动到IfElse活动的第2个分支,处理其ExecuteCode事件,代码如下。
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
UpdateModerationStatus(false, this.task1Comments); //更新审批状态
}
以上代码直接设置文档审批状态为"已拒绝"。
会签审批的实现
会签审批指的是多个人参与审批的,当审批通过数满足一定条件时,审批才算通过。本节我们继续扩展文档审批流程,使其支持多个用户同时审批,只有所有用户都批准后才发布文档,只要有一个用户拒绝,则将文档状态改为"已拒绝",并且结束会签。
使用replicator活动可以动态创建多个子活动。为简化代码,直接使用上一节开发的TaskActivity活动来实现单个任务的创建。具体操作步骤如下。
Step1 拖曳replicator活动到工作流设计器中,在replicator活动中添加一个TaskActitity活动,设计器效果如图6所示。
Step2 设置replicatorActivity1的"ExecutionType"属性为"Parallel"(并行审批),如图7所示。
replicatorActivity支持同时或顺序执行其动态创建的子活动,这里我们选择同时执行。
图6添加replicator |
图7设置属性 |
Step3 在replicatorActivity 的Initialized事件中,可给其CurrentChildData集合属性添加多个数据,每个数据表示子活动。replicatorActivity的Initialized事件处理代码如下。
///<summary>
///设置子活动数据
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void replicatorActivity1_Initialized(object sender, EventArgs e)
{
foreach (Person person in this.GetConfigurationData().ApprovalUser)
{
this.replicatorActivity1.CurrentChildData.Add(person.AccountId);
}
}
GetConfigurationData()方法用于从初始化表单中获取配置数据,为了避免序列化问题,这里没有用属性,而是用方法,代码如下。
//获取工作流配置数据,来自关联表单或初始化表单
private ConfigurationData GetConfigurationData()
{ //将配置数据反序列化为相应对象
XmlSerializer serializer = new XmlSerializer(typeof(ConfigurationData));
XmlTextReader reader = new XmlTextReader(new System.IO.StringReader(
this.workflowProperties.InitiationData));
return (ConfigurationData)serializer.Deserialize(reader);
}
Step4 处理replicatorActivity活动的ChildInitialized事件(子活动初始化),设置任务属性,代码如下。
private void replicatorActivity1_ChildInitialized(object sender,
ReplicatorChildEventArgs e)
{
TaskActivity activity = e.Activity as TaskActivity;
activity.TaskProperties = new SPWorkflowTaskProperties();
activity.TaskProperties.AssignedTo = e.InstanceData.ToString(); //设置审批人
activity.TaskProperties.TaskType = 0;
activity.TaskProperties.Title = "会签审批任务";
}
Step5 处理replicatorActivity活动的ChildCompleted事件(子活动执行完成,即审批任务完成),将任务数据保存到taskPropertiesList字段中,代码如下。
private List<SPWorkflowTaskProperties> taskPropertiesList = new List
<SPWorkflowTaskProperties>();
///<summary>
///任务完成处理
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
private void replicatorActivity1_ChildCompleted(object sender,
ReplicatorChildEventArgs e)
{
TaskActivity activity = e.Activity as TaskActivity;
taskPropertiesList.Add(activity.TaskProperties);
}
Step6 指定replicatorActivity活动的UntilCondition为code condition,代码如下。
//replicatorActivity是否结束执行
private void Until(object sender, ConditionalEventArgs e)
{
foreach (SPWorkflowTaskProperties taskProp in this.taskPropertiesList)
{
//获取任务表单的approval字段
bool approval = Convert.ToBoolean(taskProp.ExtendedProperties
["approval"]);
if (approval == false) //若已经完成的任务中有一个审批未通过则结束任务
{
e.Result = true;
return;
}
}
e.Result = this.taskPropertiesList.Count == this.replicatorActivity1.
CurrentChildData.Count;
}
以上代码检测已经完成的任务中是否有审批未通过的,若有则设置ConditionalEventArgs的Result属性为"false",结束replicatorActivity活动的执行。
Step7 replicatorActivity活动执行完成后,需要按照会签结果设置文档的状态。拖曳一个code活动到replicatorActivity活动后面,处理其ExecuteCode事件,代码如下。
//审批任务完成后的处理
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
bool allPassed = true;
string allComments = "";
foreach (SPWorkflowTaskProperties taskProp in this.taskPropertiesList)
{
bool approval = Convert.ToBoolean(taskProp.ExtendedProperties
["approval"]);
if (approval == false)
{
allPassed = false;
}
//累加审批意见
if (allComments != "")
allComments += "\n";
allComments += taskProp.AssignedTo + ":" + taskProp.ExtendedProperties
["comments"];
}
this.UpdateModerationStatus(allPassed, allComments); //修改内容审批状态
}
以上代码检测已经完成的任务中是否有未通过的,然后调用UpdateModerationStatus方法设置文档审批状态。
转载:http://book.csdn.net/bookfiles/936/10093629438.shtml