采用Visual Studio 2008 开发工作流模板(四)

工作流模板的初始化表单

初始化表单是启动流程时调用的表单,供启动流程的用户填写一些数据。在流程代码中,可以通过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  拖曳createTaskonTaskChangedcompleteTask 3个活动到设计器中。

Step3  拖曳一个code活动到设计器中,如图2所示。

2  TaskActivity

Step4  设置createTaskonTaskChangedcompleteTaskcorrelationToken属性为"taskToken"

Step5  createTaskonTaskChangedCompleteTaskTaskId绑定到活动类的taskId字段,将createTaskSpecialPermission属性绑定到活动类的specialPermission字段。

Step6  createTaskTaskProperties属性绑定到活动类的TaskProperties属性。TaskActivity的任务数据应该公开供外部调用,所以将TaskProperties声明为属性,而不是字段,如图3所示。

3 绑定到活动类的TaskProperties属性

Step7  onTaskChangedBeforePropertiesAfterProperties属性均绑定到活动类的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  处理createTaskMethodInvoking事件,代码如下。

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。处理TaskActivityTaskCompleted事件,代码如下。

       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"];

        }

以上代码将第一级审批的结果和审批意见分别记录到task1ApprovalResulttask1Comments两个全局私有变量。

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。处理TaskActivityTaskCompleted事件,代码如下。

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活动的UntilConditioncode 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;

        }

以上代码检测已经完成的任务中是否有审批未通过的,若有则设置ConditionalEventArgsResult属性为"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

原文地址:https://www.cnblogs.com/KimhillZhang/p/1530012.html