流程图.二开案例.自实现简单流程图渲染

栏目:云星空知识作者:金蝶来源:金蝶云社区发布:2024-09-16浏览:1

流程图.二开案例.自实现简单流程图渲染

【场景】自实现简单流程图渲染 【案例】采购申请单-》采购订单-》采购入库单 多单据分别关联 <1>复制表单 BOS->应用框架-》业务流程图 ![1675424606798.webp](/download/010059eee4066ee7480b8eb61d8859b4b07b.webp) 把充满的图片控件删除,把表单插件取消,挂设自定义的表单插件 ![1675424702315.webp](/download/0100344553e169ae4ae38a44325f5c465ff7.webp) <2>表单插件代码 ```csharp using Kingdee.BOS; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.ControlModel; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.Util; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DynamicFormPlugIn.BillConvert { [Kingdee.BOS.Util.HotUpdate] public class ViewTreePlugIn : AbstractDynamicFormPlugIn { public override void AfterBindData(EventArgs e) { this.View.SetFormTitle(new LocaleValue("二开流程图")); CustomTreeElement treeObj = BuildTreeObj(); WorkflowChartMetaData chart = new WorkflowChartMetaData(); chart.DesignerXml = FormatDesignXml(treeObj.BuildDesignerXml()); (this.View.GetControl("FWorkflowChart") as WorkflowChart).SetDesignerXml(chart); (this.View.GetControl("FWorkflowChart") as WorkflowChart).Visible = true; } private CustomTreeElement BuildTreeObj() { CustomTreeElement treeObj = new CustomTreeElement(); var pur_req1 = treeObj.AddBillNode("PUR_Requisition", "采购申请单", "A001"); var pur_req2 = treeObj.AddBillNode("PUR_Requisition", "采购申请单", "A002"); var pur_po1 = treeObj.AddBillNode("PUR_PurchaseOrder", "采购订单", "B001"); var pur_po2 = treeObj.AddBillNode("PUR_PurchaseOrder", "采购订单", "B002"); var pur_po3 = treeObj.AddBillNode("PUR_PurchaseOrder", "采购订单", "B003"); var stk_instk1 = treeObj.AddBillNode("STK_InStock", "采购入库单", "C001"); var stk_instk2 = treeObj.AddBillNode("STK_InStock", "采购入库单", "C002"); var stk_instk3 = treeObj.AddBillNode("STK_InStock", "采购入库单", "C003"); treeObj.AddLine(pur_req1, pur_po1); treeObj.AddLine(pur_req1, pur_po2); treeObj.AddLine(pur_req2, pur_po2); treeObj.AddLine(pur_req2, pur_po3); treeObj.AddLine(pur_po1, stk_instk2); treeObj.AddLine(pur_po2, stk_instk3); treeObj.AddLine(pur_po3, stk_instk1); return treeObj; } private string FormatDesignXml(string designerXml) { designerXml = designerXml.Replace((char)10, (char)' ').Replace((char)13, ' '); designerXml = designerXml.Replace("RefBusinessFlowElementId", "RefFlowElementId"); designerXml = designerXml.Replace("BusinessFlowElementTypeId", "FlowElementType"); designerXml = designerXml.Replace("BusinessFlowElementClass", "FlowElementClass"); designerXml = designerXml.Replace("StartActivity.webp", "StartActivityForBusiness.webp"); return designerXml; } public class CustomTreeElement : Kingdee.BOS.Core.BusinessFlow.FlowElement { public CustomTreeNodeElement AddBillNode(string formId, string formName, string billNo) { string key = string.Format("{0}_{1}", formId, billNo); CustomTreeNodeElement node = this.Nodes.FirstOrDefault((t) => t.GetKey().EqualsIgnoreCase(formId)) as CustomTreeNodeElement; if (node != null) return node; node = new CustomTreeNodeElement(formId, formName, billNo); node.NodeId = this.GetMaxSeq() + 1; this.Nodes.Add(node); return node; } public void AddLine(CustomTreeNodeElement lhs, CustomTreeNodeElement rhs) { Kingdee.BOS.Core.BusinessFlow.LineElement lineObj = null; if (!this.TryGetLine(lhs.NodeId, rhs.NodeId, out lineObj)) { var line = new CustomNodeLineElement(); line.Lhs = lhs; line.Rhs = rhs; line.LineId = this.GetMaxSeq() + 1; ; line.SourceNodeId = lhs.NodeId; line.TargetNodeId = rhs.NodeId; this.Lines.Add(line); } } public string BuildDesignerXml() { StringBuilder sb = new StringBuilder(); string xmlNodes = string.Empty; string xmlLines = string.Empty; this.BuildFlowTreeString(out xmlNodes, out xmlLines); sb.AppendLine("<Diagram Version=\"14\">"); sb.AppendLine(" <Nodes>"); sb.AppendLine(xmlNodes); sb.AppendLine(" </Nodes>"); sb.AppendLine(" <Links>"); sb.AppendLine(xmlLines); sb.AppendLine(" </Links>"); sb.AppendLine(XmlConst.XML_Properties); sb.AppendLine(XmlConst.XML_Selection); sb.AppendLine(XmlConst.XML_Resources); sb.AppendLine("</Diagram>"); return sb.ToString(); } private void BuildFlowTreeString(out string xmlNodes, out string xmlLines) { StringBuilder sbNodes = new StringBuilder(); StringBuilder sbLines = new StringBuilder(); int defaultPosX = 50; int defaultPosY = 50; int moveX = 250; int moveY = 100; Dictionary<string, Tuple<int, int>> formIdPos = new Dictionary<string, Tuple<int, int>>(); Func<string, int> getX = (formId) => { int result = 0; if (formIdPos.ContainsKey(formId)) { result = formIdPos[formId].Item1; } else { result = defaultPosX; formIdPos[formId] = new Tuple<int, int>(defaultPosX, defaultPosY); defaultPosX += moveX; } return result; }; Func<string, int> getY = (formId) => { int result = 0; if (formIdPos.ContainsKey(formId)) { var tuple = formIdPos[formId]; result = tuple.Item2; formIdPos[formId] = new Tuple<int, int>(tuple.Item1, tuple.Item2 + moveY); } else { result = defaultPosX; formIdPos[formId] = new Tuple<int, int>(defaultPosX, defaultPosY); defaultPosX += moveX; } return result; }; Dictionary<int, System.Drawing.Rectangle> nodeRect = new Dictionary<int, System.Drawing.Rectangle>(); foreach (CustomTreeNodeElement node in Nodes) { System.Drawing.Rectangle rect = new System.Drawing.Rectangle() { X = getX(node.FormId), Y = getY(node.FormId), Width = 100, Height = 50, }; nodeRect[node.NodeId] = rect; sbNodes.AppendLine("").AppendFormat(XmlConst.XML_Node, node.NodeId, string.Format("{0}, {1}, {2}, {3}", rect.X, rect.Y, rect.Width, rect.Height), node.DisplayName, node.NodeId); } foreach (var line in Lines) { var srcRect = nodeRect[line.SourceNodeId]; var tgtRect = nodeRect[line.TargetNodeId]; string beginXY, beginPoint, endXY, endPoint, beginSecXY, endSecXY; int beginPointIndex = 1, endPoingIndex = 3; this.CalcLinePoint(srcRect, tgtRect, 50, out beginXY, out beginPoint, out beginPointIndex, out endXY, out endPoint, out endPoingIndex, out beginSecXY, out endSecXY); if (!string.IsNullOrWhiteSpace(beginSecXY)) { beginXY = beginXY + "</Point><Point>" + beginSecXY; } if (!string.IsNullOrWhiteSpace(endSecXY)) { endXY = endSecXY + "</Point><Point>" + endXY; } sbLines.AppendLine("").AppendFormat(XmlConst.XML_Line, line.LineId, line.LineId, (line.SourceNodeId == 0 ? "bf:EntryNode" : "bf:Node"), line.LineId, (line.TargetNodeId == 0 ? "bf:EntryNode" : "bf:Node"), beginXY, endXY, line.LineId, beginPoint, beginPointIndex, endPoint, endPoingIndex); } xmlNodes = sbNodes.ToString(); xmlLines = sbLines.ToString(); } /// <summary> /// 计算两个节点之间的连线最佳坐标 /// </summary> /// <param name="parentNode">开始节点</param> /// <param name="childNode">结束节点</param> /// <param name="xToLeft">偏移坐标</param> /// <param name="beginXY">连线开始点的X,Y轴坐标</param> /// <param name="beginPoint"> /// 连线开始点在节点上的相对位置: /// 上 (50,0); /// 右 (100,50); /// 下 (50,100); /// 左 (0,50) /// </param> /// <param name="beginPointIndex"> /// 连线输出点,在节点连接点中的顺序,以上部开始为0,顺时针数,分别为1,2,3 /// </param> /// <param name="endXY">连线结束点的X,Y轴坐标</param> /// <param name="endPoint">连线结束点在节点上的相对位置,值含义同beginPoint</param> /// <param name="endPointIndex">含义同beginPointIndex</param> /// <param name="beginSecXY">开始第二点的X,Y坐标;在跨节点连接时,不能直接连接两节点,需要增加第二点</param> /// <param name="endSecXY">结束第二点的X,Y坐标</param> private void CalcLinePoint(System.Drawing.Rectangle parentNode, System.Drawing.Rectangle childNode, int xToLeft, out string beginXY, out string beginPoint, out int beginPointIndex, out string endXY, out string endPoint, out int endPointIndex, out string beginSecXY, out string endSecXY) { beginSecXY = ""; endSecXY = ""; decimal beginX = 0, beginY = 0, endX = 0, endY = 0; if (parentNode.X == childNode.X) {// 横坐标相同,同列 this.CalcLinePointSameX(parentNode, childNode, xToLeft, out beginXY, out beginPoint, out beginPointIndex, out endXY, out endPoint, out endPointIndex, out beginSecXY, out endSecXY); return; } else if (parentNode.Y == childNode.Y) {// 纵坐标相同,同行 this.CalcLinePointSameY(parentNode, childNode, xToLeft, out beginXY, out beginPoint, out beginPointIndex, out endXY, out endPoint, out endPointIndex, out beginSecXY, out endSecXY); return; } else if (parentNode.X < childNode.X) {// 开始节点在左: 开始节点 -> 结束节点 beginPoint = "100, 50"; beginPointIndex = 1; // 右,第2个连接点 endPoint = "0, 50"; endPointIndex = 3; // 左,第4个连接点 beginX = parentNode.X + parentNode.Width + xToLeft; beginY = parentNode.Y + parentNode.Height / 2; endX = childNode.X + xToLeft; endY = childNode.Y + childNode.Height / 2; } else {// 结束节点在左: 结束节点 <- 开始节点 beginPoint = "0, 50"; beginPointIndex = 3; // 左,第4个连接点 endPoint = "100, 50"; endPointIndex = 1; // 右,第2个连接点 beginX = parentNode.X + xToLeft; beginY = parentNode.Y + parentNode.Height / 2; endX = childNode.X + childNode.Width + xToLeft; endY = childNode.Y + childNode.Height / 2; } beginXY = string.Format("{0}, {1}", beginX, beginY); endXY = string.Format("{0}, {1}", endX, endY); } /// <summary> /// X轴坐标相同,两节点在同一列 /// </summary> private void CalcLinePointSameX(System.Drawing.Rectangle parentNode, System.Drawing.Rectangle childNode, int xToLeft, out string beginXY, out string beginPoint, out int beginPointIndex, out string endXY, out string endPoint, out int endPointIndex, out string beginSecXY, out string endSecXY) { beginSecXY = ""; endSecXY = ""; decimal beginX = 0, beginY = 0, endX = 0, endY = 0; if (Math.Abs(parentNode.Y - childNode.Y) <= 100) {// 两节点之间无其他节点,输出入连线,在上下点 beginX = parentNode.X + xToLeft + parentNode.Width / 2; endX = childNode.X + xToLeft + childNode.Width / 2; if (parentNode.Y < childNode.Y) {// 开始节点在上, 输出位置在下 beginPoint = "50, 100"; beginPointIndex = 2; // 下部,第3个连接点 endPoint = "50,0"; endPointIndex = 0; // 上部,第1个连接点 beginY = parentNode.Y + parentNode.Height; endY = childNode.Y; } else {// 开始节点在下 beginPoint = "50, 0"; beginPointIndex = 0; // 上部,第1个连接点 endPoint = "50, 100"; endPointIndex = 2; // 下部,第3个连接点 beginY = parentNode.Y; endY = childNode.Y + childNode.Height; } } else if (parentNode.Y < childNode.Y) {// 跨越了节点,开始节点在上面,从左边引出连线 beginX = parentNode.X + xToLeft; beginY = parentNode.Y + parentNode.Height / 2; endX = childNode.X + xToLeft; endY = childNode.Y + childNode.Height / 2; beginPoint = "0, 50"; beginPointIndex = 3; endPoint = "0, 50"; endPointIndex = 3; // 需要第二点 beginSecXY = string.Format("{0}, {1}", beginX - 20, beginY); endSecXY = string.Format("{0}, {1}", endX - 20, endY); } else {// 跨越了节点,开始节点在下面,从右边引出连线 beginX = parentNode.X + xToLeft + parentNode.Width; beginY = parentNode.Y + parentNode.Height / 2; endX = childNode.X + xToLeft + childNode.Width; endY = childNode.Y + childNode.Height / 2; beginPoint = "100, 50"; beginPointIndex = 1; endPoint = "100, 50"; endPointIndex = 1; // 需要第二点 beginSecXY = string.Format("{0}, {1}", beginX + 20, beginY); endSecXY = string.Format("{0}, {1}", endX + 20, endY); } beginXY = string.Format("{0}, {1}", beginX, beginY); endXY = string.Format("{0}, {1}", endX, endY); } /// <summary> /// Y轴坐标相同,两节点在同一行,且跨越了节点 /// </summary> private void CalcLinePointSameY(System.Drawing.Rectangle parentNode, System.Drawing.Rectangle childNode, int xToLeft, out string beginXY, out string beginPoint, out int beginPointIndex, out string endXY, out string endPoint, out int endPointIndex, out string beginSecXY, out string endSecXY) { beginSecXY = ""; endSecXY = ""; decimal beginX = 0, beginY = 0, endX = 0, endY = 0; if (parentNode.X < childNode.X && Math.Abs(parentNode.X - childNode.X) > 250) {// 跨越了节点,开始节点在左,从上面引出连线 beginX = parentNode.X + xToLeft + parentNode.Width / 2; beginY = parentNode.Y; endX = childNode.X + xToLeft + childNode.Width / 2; endY = childNode.Y; beginPoint = "50, 0"; beginPointIndex = 0; endPoint = "50, 0"; endPointIndex = 0; // 需要第二点 beginSecXY = string.Format("{0}, {1}", beginX, beginY - 20); endSecXY = string.Format("{0}, {1}", endX, endY - 20); } else if (parentNode.X < childNode.X) {// 开始节点 => 结束节点,未跨越,直接输出连线 beginPoint = "100, 50"; beginPointIndex = 1; // 右,第2个连接点 endPoint = "0, 50"; endPointIndex = 3; // 左,第4个连接点 beginX = parentNode.X + parentNode.Width + xToLeft; beginY = parentNode.Y + parentNode.Height / 2; endX = childNode.X + xToLeft; endY = childNode.Y + childNode.Height / 2; } else {// 开始节点在右面,从下边引出连线 beginX = parentNode.X + xToLeft + parentNode.Width / 2; beginY = parentNode.Y + parentNode.Height; endX = childNode.X + xToLeft + childNode.Width / 2; endY = childNode.Y + childNode.Height; beginPoint = "50, 100"; beginPointIndex = 2; endPoint = "50, 100"; endPointIndex = 2; // 需要第二点 beginSecXY = string.Format("{0}, {1}", beginX, beginY + 20); endSecXY = string.Format("{0}, {1}", endX, endY + 20); } beginXY = string.Format("{0}, {1}", beginX, beginY); endXY = string.Format("{0}, {1}", endX, endY); } } public static class XmlConst { #region XML片段 /// <summary> /// 开始节点的XML内容,使用时,需替换其中的替代符 /// {0} = Seq (0 开始); /// {1} = Bounds 310,20,165,36; /// {2} = ItemName; /// {3} = NodeId ; /// </summary> public const string XML_EntryNode = @" <Node Class=""bf:EntryNode"" Version=""1"" Id=""{0}""> <ZIndex>{0}</ZIndex> <HyperLink /> <Locked>False</Locked> <Visible>True</Visible> <Brush Id=""0"" /> <Pen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </Pen> <Unit>7</Unit> <Italic>False</Italic> <IgnoreLayout>False</IgnoreLayout> <HandlesStyle>8</HandlesStyle> <Stroke Id=""1"" /> <StrokeThickness>1</StrokeThickness> <StrokeDashOffset>0</StrokeDashOffset> <Bounds>{1}</Bounds> <AnchorPattern Id=""""> <Points Count=""4""> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>50</X> <Y>0</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>100</X> <Y>50</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>50</X> <Y>100</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>0</X> <Y>50</Y> </AnchorPoint> </Points> </AnchorPattern> <Constraints> <Constraint Type=""1""> <Value>0</Value> </Constraint> <Constraint Type=""2""> <Value>0</Value> </Constraint> <Constraint Type=""3""> <Value>0</Value> </Constraint> <Constraint Type=""4""> <Value>0</Value> </Constraint> <Constraint Type=""5""> <Value>False</Value> </Constraint> <Constraint Type=""6""> <Value>False</Value> </Constraint> <Constraint Type=""7""> <Value>False</Value> </Constraint> </Constraints> <Obstacle>True</Obstacle> <AllowIncomingLinks>True</AllowIncomingLinks> <AllowOutgoingLinks>True</AllowOutgoingLinks> <EnabledHandles>256</EnabledHandles> <Expanded>True</Expanded> <Expandable>False</Expandable> <Shape Id=""Rectangle"" /> <Text /> <TextColor>#FF000000</TextColor> <TextFormat> <Alignment>1</Alignment> <LineAlignment>1</LineAlignment> </TextFormat> <Image Id=""0"" /> <ImageAlign>1</ImageAlign> <Transparent>False</Transparent> <ImageWebLocation>http://localhost:1200/images/silverlight/default/workflowdesigner/bf_EntryNode.webp</ImageWebLocation> <TextAlignment>0</TextAlignment> <HorizontalTextBlockAlignment>1</HorizontalTextBlockAlignment> <VerticalTextBlockAlignment>1</VerticalTextBlockAlignment> <ItemName>{2}</ItemName> <FlowElementClass /> <RefFlowElementId>{3}</RefFlowElementId> <NodeImgKey>bf_EntryNode.webp</NodeImgKey> </Node> "; /// <summary> /// 普通节点的XML片段,使用时,需替换占位符 /// {0} = Seq (0 开始); /// {1} = Bounds 310,20,165,36 ; /// {2} = ItemName ; /// {3} = NodeId; /// </summary> public const string XML_Node = @" <Node Class=""bf:Node"" Version=""1"" Id=""{0}""> <ZIndex>{0}</ZIndex> <HyperLink /> <Locked>False</Locked> <Visible>True</Visible> <Brush Id=""0"" /> <Pen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </Pen> <Unit>7</Unit> <Italic>False</Italic> <IgnoreLayout>False</IgnoreLayout> <HandlesStyle>8</HandlesStyle> <Stroke Id=""1"" /> <StrokeThickness>1</StrokeThickness> <StrokeDashOffset>0</StrokeDashOffset> <Bounds>{1}</Bounds> <AnchorPattern Id=""""> <Points Count=""4""> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>50</X> <Y>0</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>100</X> <Y>50</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>50</X> <Y>100</Y> </AnchorPoint> <AnchorPoint> <AllowIncoming>True</AllowIncoming> <AllowOutgoing>True</AllowOutgoing> <Color>#FF000000</Color> <Column>-1</Column> <MarkStyle>3</MarkStyle> <Tooltip /> <X>0</X> <Y>50</Y> </AnchorPoint> </Points> </AnchorPattern> <Constraints> <Constraint Type=""1""> <Value>0</Value> </Constraint> <Constraint Type=""2""> <Value>0</Value> </Constraint> <Constraint Type=""3""> <Value>0</Value> </Constraint> <Constraint Type=""4""> <Value>0</Value> </Constraint> <Constraint Type=""5""> <Value>False</Value> </Constraint> <Constraint Type=""6""> <Value>False</Value> </Constraint> <Constraint Type=""7""> <Value>False</Value> </Constraint> </Constraints> <Obstacle>True</Obstacle> <AllowIncomingLinks>True</AllowIncomingLinks> <AllowOutgoingLinks>True</AllowOutgoingLinks> <EnabledHandles>256</EnabledHandles> <Expanded>True</Expanded> <Expandable>False</Expandable> <Shape Id=""Rectangle"" /> <Text /> <TextColor>#FF000000</TextColor> <TextFormat> <Alignment>1</Alignment> <LineAlignment>1</LineAlignment> </TextFormat> <Image Id=""0"" /> <ImageAlign>1</ImageAlign> <Transparent>False</Transparent> <ImageWebLocation>http://localhost:1200/images/silverlight/default/workflowdesigner/bf_Node.webp</ImageWebLocation> <TextAlignment>0</TextAlignment> <HorizontalTextBlockAlignment>1</HorizontalTextBlockAlignment> <VerticalTextBlockAlignment>1</VerticalTextBlockAlignment> <ItemName>{2}</ItemName> <FlowElementClass>Kingdee.BOS.Core.BusinessFlow.BillNodeElement,Kingdee.BOS.Silverlight.Core, Version=0.0.0.0</FlowElementClass> <RefFlowElementId>{3}</RefFlowElementId> <NodeImgKey>bf_Node.webp</NodeImgKey> </Node> "; /// <summary> /// 连线的XML片段,使用时,需替换占位符: /// {0} = Seq (Node.count 开始); /// {1} = 开始节点的Seq; /// {2} = 开始节点类型 bf:EntryNode, 普通节点类型 bf:Node ; /// {3} = 结束节点的Seq ; /// {4} = 开始节点类型 bf:EntryNode, 普通节点类型 bf:Node ; /// {5} = Point 1 <point>392.5, 56</point> ; /// {6} = Point 2 <point>392.5, 130</point> ; /// {7} = LineId ; /// {8} = OriginRelative 输出点 100,50; 以左上角为0,0为参考坐标 /// {9} = OriginAnchor, 全部4个连接点的顺序,以上部为0开始,顺时针数 /// {10} = Destination 输入点 0,50; /// {11} = DestinationAnchor, 同OrginAnchor /// </summary> public const string XML_Line = @" <Link Class=""bf:Link"" Version=""1"" Id=""{0}""> <ZIndex>{0}</ZIndex> <HyperLink /> <Locked>False</Locked> <Visible>True</Visible> <Brush Id=""2"" /> <Pen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </Pen> <Unit>7</Unit> <Italic>False</Italic> <IgnoreLayout>False</IgnoreLayout> <HandlesStyle>1</HandlesStyle> <Stroke Id=""1"" /> <StrokeThickness>1</StrokeThickness> <StrokeDashOffset>0</StrokeDashOffset> <StrokeDashArray /> <Origin Id=""{1}"" ClassId=""{2}"" Version=""1"" /> <OriginRelative>{8}</OriginRelative> <OriginAnchor>{9}</OriginAnchor> <Destination Id=""{3}"" ClassId=""{4}"" Version=""1"" /> <DestinationRelative>{10}</DestinationRelative> <DestinationAnchor>{11}</DestinationAnchor> <Style>1</Style> <SegmentCount>1</SegmentCount> <Points> <Point>{5}</Point> <Point>{6}</Point> </Points> <Dynamic>False</Dynamic> <AutoRoute>True</AutoRoute> <CascadeOrientation>0</CascadeOrientation> <CascadeStartHorizontal>True</CascadeStartHorizontal> <Text /> <AllowMoveStart>True</AllowMoveStart> <AllowMoveEnd>True</AllowMoveEnd> <HeadPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </HeadPen> <HeadShape Id=""Triangle"" /> <HeadShapeSize>13</HeadShapeSize> <BaseShapeSize>13</BaseShapeSize> <IntermediateShapeSize>13</IntermediateShapeSize> <RefFlowElementId>{7}</RefFlowElementId> </Link> "; /// <summary> /// 连线的转折点,使用时,需替换其中的坐标 /// </summary> public const string XML_LinePoint = @" <Point>{0}</Point> "; public const string XML_Properties = @" <Properties> <LinkHeadShape Id=""Triangle"" /> <LinkHeadShapeSize>13</LinkHeadShapeSize> <LinkBaseShapeSize>13</LinkBaseShapeSize> <LinkIntermediateShapeSize>13</LinkIntermediateShapeSize> <AlignToGrid>False</AlignToGrid> <ShowGrid>False</ShowGrid> <GridStyle>0</GridStyle> <GridColor>#FF000000</GridColor> <GridSizeX>20</GridSizeX> <GridSizeY>20</GridSizeY> <GridOffsetX>0</GridOffsetX> <GridOffsetY>0</GridOffsetY> <GridPointSize>5</GridPointSize> <LinkStyle>1</LinkStyle> <LinkSegments>1</LinkSegments> <Bounds>0, 0, 2000, 2000</Bounds> <TableRowsCount>4</TableRowsCount> <TableColumnsCount>2</TableColumnsCount> <TableColumnWidth>40</TableColumnWidth> <TableRowHeight>20</TableRowHeight> <TableCaptionHeight>20</TableCaptionHeight> <TableCaption>Table</TableCaption> <NodesExpandable>False</NodesExpandable> <Unit>7</Unit> <Italic>False</Italic> <DefaultShape Id=""RoundRect"" /> <ShapePen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </ShapePen> <LinkPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </LinkPen> <ShapeBrush Id=""0"" /> <LinkBrush Id=""2"" /> <Brush Id=""3"" /> <AllowUnconnectedLinks>False</AllowUnconnectedLinks> <RouteLinks>True</RouteLinks> <MeasureUnit>7</MeasureUnit> <ExpandBtnPos>0</ExpandBtnPos> <ExpandButtonBrush Id=""4"" /> <LinkCrossings>1</LinkCrossings> <CrossRadius>5</CrossRadius> <RoundedLinks>True</RoundedLinks> <RoundedLinksRadius>0</RoundedLinksRadius> <EnableLanes>False</EnableLanes> <Lane> <LeftMargin>0</LeftMargin> <TopMargin>0</TopMargin> <MinHeaderSize>40</MinHeaderSize> <HookHeaders>False</HookHeaders> <HeadersOnTop>True</HeadersOnTop> <RowWidths /> <ColumnHeights /> <AllowResizeHeaders>True</AllowResizeHeaders> <Columns> <Width>0</Width> <Height>0</Height> <ResizeType>1</ResizeType> <Title /> <Style> <BackgroundBrush Id=""5"" /> <LeftBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </LeftBorderPen> <TopBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </TopBorderPen> <RightBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </RightBorderPen> <BottomBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </BottomBorderPen> </Style> <SubHeaders /> </Columns> <Rows> <Width>0</Width> <Height>0</Height> <ResizeType>1</ResizeType> <Title /> <Style> <BackgroundBrush Id=""5"" /> <LeftBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </LeftBorderPen> <TopBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </TopBorderPen> <RightBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </RightBorderPen> <BottomBorderPen> <Brush Id=""1"" /> <DashOffset>0</DashOffset> <DashStyle>0</DashStyle> <Width>1</Width> </BottomBorderPen> </Style> <SubHeaders /> </Rows> <Cells ColumnCount=""0"" RowCount=""0"" /> </Lane> <AdjustmentHandlesSize>8</AdjustmentHandlesSize> <HitTestPriority>1</HitTestPriority> <AutoResize>1</AutoResize> </Properties> "; public const string XML_Selection = @" <Selection />"; /// <summary> /// 输出的XML中,Resources部分内容 /// </summary> public const string XML_Resources = @" <Resources> <Brushes> <Brush Index=""0"" Type=""Solid""> <Color>#64DCDCFF</Color> </Brush> <Brush Index=""1"" Type=""Solid""> <Color>#FF000000</Color> </Brush> <Brush Index=""2"" Type=""Solid""> <Color>#FF78DCFF</Color> </Brush> <Brush Index=""3"" Type=""Solid""> <Color>#FFFFFFFF</Color> </Brush> <Brush Index=""4"" Type=""Solid""> <Color>#F0C8C8C8</Color> </Brush> <Brush Index=""5"" Type=""Solid""> <Color>#FFFFFFFF</Color> </Brush> </Brushes> <Images Count=""0""/> </Resources> "; #endregion XML 片段 } /// <summary> /// 自定义节点控件 /// </summary> public class CustomTreeNodeElement : Kingdee.BOS.Core.BusinessFlow.NodeElement { public CustomTreeNodeElement(string formId, string formName, string billNo) { FormId = formId; DisplayName = new LocaleValue(string.Format("{0}:{1}", formName, billNo)); } public readonly string FormId; public readonly string BillNo; public override string GetKey() { return string.Format("{0}_{1}",FormId, BillNo); } } /// <summary> /// 自定义线控件 /// </summary> public class CustomNodeLineElement : Kingdee.BOS.Core.BusinessFlow.LineElement { public CustomTreeNodeElement Lhs; public CustomTreeNodeElement Rhs; } } } ``` 核心代码块 <1>构造节点和关系BuildTreeObj 【效果】 ![1675424024323.webp](/download/0100b26d7049f1b44fe791820ad54645972d.webp)

流程图.二开案例.自实现简单流程图渲染

【场景】自实现简单流程图渲染【案例】采购申请单-》采购订单-》采购入库单多单据分别关联<1>复制表单 BOS->应用框架-》业务流程图![16754...
点击下载文档
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息