5.7 开发工作流图形定义工具
5.7.6 图形工具主界面程序
......(接前页)
//删除节点
private void menuItem1_Click(object sender, System.EventArgs e)
{
//如果右键选择了节点
if(R_pickednode != null)
{
//定义临时节点
NodeClass editednode = null;
//如果删除的是逻辑节点,首先要设置相应的任务节点的processlogic属性为空
if(R_pickednode.NodeType == nodetypedefine.andsplit || R_pickednode.NodeType
== nodetypedefine.orsplit)
{
//如果存在指向逻辑节点的迁移
if(transitionarray.GetToNodeTransition(R_pickednode.NodeName) != null)
//获取分支节点的前驱任务节点
editednode = nodearray.GetNode(transitionarray
.GetToNodeTransition(R_pickednode.NodeName).GetTransition(0).FromNode);
//考虑具有双重逻辑属性的节点
if(editednode.ProcessLogic == "AndJoin&OrSplit")
editednode.ProcessLogic = "AndJoin";
......
else//如果只包含单重逻辑属性的
editednode.ProcessLogic="";
}
if(R_pickednode.NodeType == nodetypedefine.andjoin || R_pickednode.NodeType
== nodetypedefine.orjoin)
{
//如果存在从合并节点引出的迁移
if(transitionarray.GetFromNodeTransition(R_pickednode.NodeName) != null)
{
editednode = nodearray.GetNode(transitionarray.GetFromNodeTransition
(R_pickednode.NodeName).GetTransition(0).ToNode);
//考虑具有双重逻辑属性的节点
if(editednode.ProcessLogic == "AndJoin&OrSplit")
editednode.ProcessLogic = "OrSplit";
......
else//如果只包含单重逻辑属性的
editednode.ProcessLogic="";
}
}
//删除节点和关联的迁移
transitionarray.DeleteTransition(R_pickednode.NodeName);
nodearray.DeleteNode(R_pickednode);
//只有一个节点时,删除后不消失(不知什么原因),增加了下面语句
g=panel1.CreateGraphics();
g.FillRectangle(new SolidBrush(this.BackColor),0,0,this.Width,this.Height);
g.Dispose();
R_pickednode=null;
repaint();
}//如果右键选择了节点
}
//编辑节点属性
private void menuItem2_Click(object sender, System.EventArgs e)
{
if(R_pickednode != null)
{
if( R_pickednode.NodeType == nodetypedefine.tasknode)
{
//记录节点原名称
string oldname=R_pickednode.NodeName;
//初始化节点编辑窗
EditNode editnode=new EditNode();
editnode.setNameText(R_pickednode.NodeName);
editnode.ShowDialog();
if(editnode.nodename == "")
MessageBox.Show("节点名称不能为空!");
else
{
//判断输入的节点名程是否与其它节点重复
//先把当前节点名置为空,以便只检查其它节点
string tempstr=R_pickednode.NodeName;
R_pickednode.NodeName="";
if(nodearray.GetNode(editnode.nodename.Trim()) != null)
{
R_pickednode.NodeName=tempstr;
MessageBox.Show("节点名称重复!");
}
else
{
R_pickednode.NodeName=editnode.nodename.Trim();
//按照原名称获取所有指向所选节点的迁移
TransitionRecords pretransitions=transitionarray
.GetToNodeTransition(oldname);
//如果存在指向所选节点的迁移
if(pretransitions != null)
{
for(int i=0;i<pretransitions.Count;i++)
pretransitions.GetTransition(i).ToNode
=R_pickednode.NodeName;
}
TransitionRecords nexttransitions=transitionarray
.GetFromNodeTransition(oldname);
//如果存在从所选节点引出的迁移
if(nexttransitions != null)
{
for(int i=0;i<nexttransitions.Count;i++)
nexttransitions.GetTransition(i).FromNode
=R_pickednode.NodeName;
}
}//else
}//else
}//if( R_pickednode.NodeType == nodetypedefine.tasknode)
R_pickednode=null;
}//if(R_pickednode != null)
}
//绘图面板重画事件处理函数
private void Panel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
repaint();
}
//把流程及节点保存到数据库
private void menuItem5_Click(object sender, System.EventArgs e)
{
//检查节点数组的正确性
if(! CheckProcessModel())
return;
//编辑过程属性
ProcessForm processform=new ProcessForm();
processform.ShowDialog();
if(processform.processDes == "")
{
MessageBox.Show("流程名称不能为空!");
return;
}
else if(processform.duedate == "")
{
MessageBox.Show("承诺期限不能为空!");
return;
}
else
{
if(processform.processDes.Length > 50)
{
MessageBox.Show("流程名称太长!");
return;
}
DataAccess database=new DataAccess();
//判断流程名称是否已经存在
string strSql="select ProcessID from ProcessDefinition where
ProcessName=@ProcessName";
SqlCommand cmd=new SqlCommand(strSql);
cmd.Parameters.Add("@ProcessName",SqlDbType.VarChar,50);
cmd.Parameters["@ProcessName"].Value=processform.processDes;
if(database.IfExistRecord(cmd))
{
MessageBox.Show("流程名称已经存在!");
return;
}
//保存流程
//获得该流程关联的业务表的标识字段名
string tablename=processform.relatedTableName;
string tablealias=processform.tableAlias;
strSql="Select name from syscolumns Where ID=OBJECT_ID('"+tablename+"') and
autoval is not null";
DataSet ds=database.SQLExeDataSet(strSql);
if(ds == null)
{
MessageBox.Show("获取业务表标识字段名失败!");
return;
}
if(ds.Tables[0].Rows.Count<1 )
{
MessageBox.Show("数据表"+tablename+"没有定义标识字段,不能进行流程关联.流
程定义无法继续进行.");
return;
}
string identityfield=ds.Tables[0].Rows[0]["name"].ToString();
//保存过程和节点
int processid=nodearray.SaveProcess(processform.processDes,tablename,
tablealias,identityfield,processform.duedate);
if( processid == -1)
return;
//保存迁移
if(! transitionarray.SaveTransitions(nodearray,processid))
return;
}//else
}
//检查节点数组的正确性
private bool CheckProcessModel()
{
//检查模型的正确性
//至少要包含开始、结束和2个任务节点
if(nodearray.Count < 3)
{
MessageBox.Show("流程至少要包含开始、结束和任务节点!");
return false;
}
//是否有开始节点
bool hasstartnode=false;
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType == nodetypedefine.start)
{
hasstartnode=true;
break;
}
}
if(! hasstartnode)
{
MessageBox.Show("没有开始节点!");
return false;
}
//是否有结束节点
bool hasendnode=false;
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType == nodetypedefine.end)
{
hasendnode=true;
break;
}
}
if(! hasendnode)
{
MessageBox.Show("没有结束节点!");
return false;
}
//除了开始节点,所有节点都必须存在前驱;除了结束节点,所有节点都必须存在后继。
//检查前驱
bool prenode=true;
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType != nodetypedefine.start)
{
if(transitionarray.GetToNodeTransition(nodearray.GetNode(i).NodeName)
== null)
{
prenode=false;
break;
}
}
}
if(! prenode)
{
MessageBox.Show("除开始节点外还存在没有前驱的节点!");
return false;
}
//检查后继
bool nextnode=true;
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType != nodetypedefine.end)
{
if(transitionarray.GetFromNodeTransition(nodearray.GetNode(i).NodeName)
== null)
{
nextnode=false;
break;
}
}
}
if(! nextnode)
{
MessageBox.Show("除结束节点外还存在没有后继的节点!");
return false;
}
//过程的连通性检查已没必要,有了画图时的迁移的单向性检查,以及过程的完整性检查和
//过程嵌套约束,已经可以满足连通性;“或分支最多只能包含一个旁路”的约束不必检
//查,因为在画图时已经检查了“两个节点(包括或分支与或连接节点)间只能有一个迁
//移”的约束。
//或分支至少要有一个路径包含任务节点
bool includetask=true;
NodeClass tempnode=null;
TransitionRecords temparray=null;
for(int i=0;i<nodearray.Count;i++)
{
tempnode=nodearray.GetNode(i);
//如果第i个节点是或分支节点
if(tempnode.NodeType == nodetypedefine.orsplit)
{
includetask=false;
//获取从或分支节点引出的所有迁移
temparray=transitionarray.GetFromNodeTransition(tempnode.NodeName);
for(int j=0;j<temparray.Count;j++)
{
if(nodearray.GetNode(temparray.GetTransition(j).ToNode).NodeType
== nodetypedefine.tasknode)
{
includetask=true;
break;
}
}
}
//如果有或分支没有任何路径包含任务节点(只有一个旁路)
if(! includetask)
break;
}//外层for循环
if(! includetask)
{
MessageBox.Show("或分支至少要有一个包含任务节点的分支!");
return false;
}
//过程逻辑的嵌套约束:每一个And Split分支节点的第一个后继过程逻辑节点只能是
//And Join连接节点
bool nested=false;
tempnode=null;
temparray=null;
//遍历节点数组,检查每一个andsplit节点
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType == nodetypedefine.andsplit)
{
//获取andsplit的所有后继迁移
temparray=transitionarray.GetFromNodeTransition(nodearray.GetNode(i)
.NodeName);
if(temparray != null)
{
//循环检查andsplit的每一个分支
for(int j=0;j<temparray.Count;j++)
{
tempnode=nodearray.GetNode(temparray.GetTransition(j).ToNode);
//调用递归函数检查。如果存在嵌套或不对称,则终止当前循环
if(AndNestedCheck(tempnode))
{
nested=true;
break;
}
}
}
//如果发现了嵌套或不对称则退出外层循环,不再继续检查下一个andsplit节点
if(nested == true)
break;
}
}//遍历节点数组的for循环
//如果存在嵌套或不对称则返回检查结果
if(nested)
{
MessageBox.Show("存在过程逻辑嵌套或者过程逻辑不对称!");
return false;
}
//orsplit过程逻辑的嵌套约束:每一个Or Split分支节点的第一个后继过程逻辑节点只能
//是Or Join连接节点
nested=false;
tempnode=null;
temparray=null;
//遍历节点数组,检查每一个orsplit节点
for(int i=0;i<nodearray.Count;i++)
{
if(nodearray.GetNode(i).NodeType == nodetypedefine.orsplit)
{
//获取orsplit的所有后继迁移
temparray=transitionarray.GetFromNodeTransition(nodearray.GetNode(i)
.NodeName);
if(temparray != null)
{
//检查orsplit的每一个分支
for(int j=0;j<temparray.Count;j++)
{
tempnode=nodearray.GetNode(temparray.GetTransition(j).ToNode);
//递归检查分支的后继节点。如果存在嵌套或不对称,则终止当前循环
if(OrNestedCheck(tempnode))
{
nested=true;
break;
}
}
}
//如果发现了嵌套或不对称则退出外层循环,不再继续检查下一个orsplit节点
if(nested == true)
break;
}
}//外层for循环
//如果存在嵌套或不对称则返回检查结果
if(nested)
{
MessageBox.Show("存在过程逻辑嵌套或者过程逻辑不对称!");
return false;
}
return true;
}//CheckProcessModel()
......(待续)