diff --git a/src/IFoxCAD.Cad/ExtensionMethod/XrefEx.cs b/src/IFoxCAD.Cad/ExtensionMethod/XrefEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..2a39873e974aac01bf54b965c9aa4d23ed66157f --- /dev/null +++ b/src/IFoxCAD.Cad/ExtensionMethod/XrefEx.cs @@ -0,0 +1,492 @@ +namespace IFoxCAD.Cad; +//对XBindXrefs,BindXrefs双重绑定参照释义的具体解析详个人第一原创的博客随笔 +// + +/// +/// 表示累计要绑定符号表类型数量的枚举 +/// 最小为0,最大为4 +/// 具体【0为"图层表",1为"文字样式表",2为"标注样式表",3为"线型表",4为"注册应用程序表"】 +/// 如选择TextStyleTable = 1,则表示累计要绑定图层表和文字样式表,以此类推 +/// +public enum XrefSymTabTypeNum +{ + /// + /// 图层表,"无敌绑定"项 + /// + LayerTable = 0, + /// + /// 文字样式表 + /// + TextStyleTable = 1, + /// + /// 标注样式表 + /// + DimStyleTable = 2, + /// + /// 线性表 + /// + LinetypeTable = 3, + /// + /// 注册应用程序表 + /// + RegAppTable = 4 +} + +/// +/// 双重绑定参照扩展类 +/// +public static class XrefEx +{ + /// + /// 利用两个原生方法双重绑定参照 + /// 可内部删除被卸载的嵌套参照 + /// 该方法仅用于"无敌绑定"项,其他项有异常eWasOpenForNotify + /// + /// 数据库 + /// 询问是否删除被卸载的嵌套参照,默认为true + /// 主要用于处理要绑定图纸中存在嵌套参照被卸载的情况 + /// 若为false,则嵌套参照将被重载绑定后保留在图纸中 + /// 无返回值 + public static void XBindXrefs(Database db, bool isEaseNested = true) + { + var workingDb = HostApplicationServices.WorkingDatabase;//数据库转换 + HostApplicationServices.WorkingDatabase = db;//数据库转换 + + db.ResolveXrefs(false, false);//解析数据库 + + var bindXrefsIds = new ObjectIdCollection();//要BindXrefs的集合 + var xBindXrefsIds = new ObjectIdCollection();//要XBindXrefs的集合 + + var isNestedNodeNameList = new List();//要处理的嵌套参照名称列表 + var isNestedIds = new ObjectIdCollection();//要处理的嵌套参照ObjectId集合 + + using (var tr = db.TransactionManager.StartTransaction()) + { + #region 原块表参照的id集合获取 + var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);//块表 + foreach (ObjectId id in bt) + { + var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead); + if (btr.IsFromExternalReference && btr.IsResolved) + bindXrefsIds.Add(id); + } + #endregion + + #region 补充是否被嵌套卸载的处理 + XrefGraph xg = db.GetHostDwgXrefGraph(true); + int xrefcount = xg.NumNodes; + for (int j = 0; j < xrefcount; j++) + { + XrefGraphNode xrNode = xg.GetXrefNode(j); + if (xrNode.XrefStatus == XrefStatus.Unloaded)//若文件已卸载 + { + ObjectId deTachId = xrNode.BlockTableRecordId; + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(deTachId, OpenMode.ForRead); + if (btr.IsFromExternalReference) + { + if (!xrNode.IsNested)//若为非嵌套参照 + { + db.DetachXref(deTachId);//拆离已经卸载的非嵌套文件 + } + else//若为嵌套参照 + { + isNestedIds.Add(deTachId); + isNestedNodeNameList.Add(xrNode.Name);//有嵌套参照,添加名称进列表,以供绑定后是否做删除处理 + } + } + } + if (xrNode.XrefStatus == XrefStatus.Unreferenced)//若文件未参照 + { + db.DetachXref(xrNode.BlockTableRecordId);//拆离未参照的文件 + } + #region 使用此方法添加的xrNode.BlockTableRecordId,绑定中会随机出现异常(勿用) + //if (xrNode.XrefStatus == XrefStatus.Resolved)//若文件已解析 + //{ + // ObjectId bindXrefId = xrNode.BlockTableRecordId; + // BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bindXrefId, OpenMode.ForRead); + // if (btr.IsFromExternalReference) + // { + // xrefIds.Add(bindXrefId); + // } + //} + #endregion + } + #endregion + + #region "无敌绑定"项 + LayerTable layert = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;//图层表 + foreach (ObjectId id in layert) + { + LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(id, OpenMode.ForRead); + if (ltr.IsResolved) + { + xBindXrefsIds.Add(ltr.ObjectId); + } + } + #endregion + + if (isNestedIds.Count > 0)//若有嵌套参照被卸载,重载 + { + db.ReloadXrefs(isNestedIds); + } + + #region 此处即为二者结合使用,且顺序非常重要。若交换秩序,则会绑定无效,切勿交换 + db.XBindXrefs(xBindXrefsIds, true);//建议为true + db.BindXrefs(bindXrefsIds, true);//建议为true + #endregion + + #region 内部删除嵌套参照的块操作 + if (isEaseNested) + { + if (isNestedNodeNameList.Count > 0 && isNestedNodeNameList != null) + { + isNestedNodeNameList.ForEach(blockName => + { + if (bt.Has(blockName)) + { + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockName], OpenMode.ForWrite); + if (btr != null) + { + btr.Erase(); + } + } + }); + } + } + #endregion + } + HostApplicationServices.WorkingDatabase = workingDb;//数据库转换 + } + /// + /// 利用两个原生方法双重绑定参照 + /// 1.增加绑定符号表累计的选择,LayerTable=0时,即单选图层表为"无敌绑定"项 + /// 2.增加储存被卸载嵌套参照名称及句柄的字典,以ref方式传出方法 + /// 提供外部处理嵌套参照的数据,绑定后若不处理,则将被保留在图纸中 + /// + /// 数据库 + /// 储存被卸载嵌套参照名称及句柄的字典 + /// 主要用于处理要绑定图纸中存在嵌套参照被卸载的情况 + /// 累计要绑定的符号表数量,默认为LayerTable=0"无敌绑定"项.最小为0,最大为4 + /// 具体【0为"图层表",1为"文字样式表",2为"标注样式表",3为"线型表",4为"注册应用程序表"】 + /// 无返回值,以ref方式传出被卸载嵌套参照名称及句柄的字典 + public static void XBindXrefs(Database db, ref Dictionary isNestedNodeNameDic, XrefSymTabTypeNum xrefSymTabTypeNum = XrefSymTabTypeNum.LayerTable) + { + var workingDb = HostApplicationServices.WorkingDatabase;//数据库转换 + HostApplicationServices.WorkingDatabase = db;//数据库转换 + + db.ResolveXrefs(false, false);//解析数据库 + + Dictionary isNestedNodeName = isNestedNodeNameDic;//要处理的嵌套参照的数据字典 + + var bindXrefsIds = new ObjectIdCollection();//声明要BindXrefs的集合 + var xBindXrefsIds = new ObjectIdCollection();//声明要XBindXrefs的集合 + var isNestedIds = new ObjectIdCollection();//要处理的嵌套参照ObjectId集合 + + using (var tr = db.TransactionManager.StartTransaction()) + { + #region 原块表参照的id集合获取 + var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);//块表 + foreach (ObjectId id in bt) + { + var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead); + if (btr.IsFromExternalReference && btr.IsResolved) + bindXrefsIds.Add(id); + } + #endregion + + #region 补充是否被嵌套卸载的处理 + XrefGraph xg = db.GetHostDwgXrefGraph(true); + int xrefcount = xg.NumNodes; + for (int j = 0; j < xrefcount; j++) + { + XrefGraphNode xrNode = xg.GetXrefNode(j); + if (xrNode.XrefStatus == XrefStatus.Unloaded)//若文件已卸载 + { + ObjectId deTachId = xrNode.BlockTableRecordId; + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(deTachId, OpenMode.ForRead); + if (btr.IsFromExternalReference) + { + if (!xrNode.IsNested)//若为非嵌套参照 + { + db.DetachXref(deTachId);//拆离已经卸载的非嵌套文件 + } + else//若为嵌套参照 + { + isNestedIds.Add(deTachId); + isNestedNodeName.Add(deTachId.Handle, xrNode.Name);//有嵌套参照,添加关键信息进字典,以传出方法供绑定后删除处理 + } + } + } + if (xrNode.XrefStatus == XrefStatus.Unreferenced)//若文件未参照 + { + db.DetachXref(xrNode.BlockTableRecordId);//拆离未参照的文件 + } + #region 使用此方法添加的xrNode.BlockTableRecordId,绑定中会随机出现异常(勿用) + //if (xrNode.XrefStatus == XrefStatus.Resolved)//若文件已解析 + //{ + // ObjectId bindXrefId = xrNode.BlockTableRecordId; + // BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bindXrefId, OpenMode.ForRead); + // if (btr.IsFromExternalReference) + // { + // xrefIds.Add(bindXrefId); + // } + //} + #endregion + } + #endregion + + #region 添加XBindXrefs符号表记录id。根据symbolTableRecordNum值范围0~4动态控制5个符号表记录累加绑定需求 + int symbolTableRecordNum = 0; + switch (xrefSymTabTypeNum) + { + case XrefSymTabTypeNum.LayerTable: + symbolTableRecordNum = 0; + break; + case XrefSymTabTypeNum.TextStyleTable: + symbolTableRecordNum = 1; + break; + case XrefSymTabTypeNum.DimStyleTable: + symbolTableRecordNum = 2; + break; + case XrefSymTabTypeNum.LinetypeTable: + symbolTableRecordNum = 3; + break; + case XrefSymTabTypeNum.RegAppTable: + symbolTableRecordNum = 4; + break; + } + if (symbolTableRecordNum >= 0)//为0时被本人称为"无敌绑定"项 + { + LayerTable layert = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;//图层表 + foreach (ObjectId id in layert) + { + LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(id, OpenMode.ForRead); + if (ltr.IsResolved) + { + xBindXrefsIds.Add(ltr.ObjectId); + } + } + } + if (symbolTableRecordNum >= 1) + { + TextStyleTable textstylet = tr.GetObject(db.TextStyleTableId, OpenMode.ForRead) as TextStyleTable;//文字样式表 + foreach (ObjectId id1 in textstylet) + { + TextStyleTableRecord textstyletr = (TextStyleTableRecord)tr.GetObject(id1, OpenMode.ForRead); + if (textstyletr.IsResolved) + { + xBindXrefsIds.Add(textstyletr.ObjectId); + } + } + } + if (symbolTableRecordNum >= 2) + { + LinetypeTable linetypet = tr.GetObject(db.LinetypeTableId, OpenMode.ForRead) as LinetypeTable;//线型表 + foreach (ObjectId id1 in linetypet) + { + LinetypeTableRecord linetr = (LinetypeTableRecord)tr.GetObject(id1, OpenMode.ForRead); + if (linetr.IsResolved) + { + xBindXrefsIds.Add(linetr.ObjectId); + } + } + } + if (symbolTableRecordNum >= 3) + { + DimStyleTable dimt = tr.GetObject(db.DimStyleTableId, OpenMode.ForRead) as DimStyleTable;//标注样式表 + foreach (ObjectId id1 in dimt) + { + DimStyleTableRecord dtr = (DimStyleTableRecord)tr.GetObject(id1, OpenMode.ForRead); + if (dtr.IsResolved) + { + xBindXrefsIds.Add(dtr.ObjectId); + } + } + } + if (symbolTableRecordNum >= 4) + { + RegAppTable regappt = tr.GetObject(db.RegAppTableId, OpenMode.ForRead) as RegAppTable;//注册应用程序表 + foreach (ObjectId id1 in regappt) + { + RegAppTableRecord regapptr = (RegAppTableRecord)tr.GetObject(id1, OpenMode.ForRead); + if (regapptr.IsResolved) + { + xBindXrefsIds.Add(regapptr.ObjectId); + } + } + } + #region 起初测试是将9大符号表记录均加入的,但经实测不行。所以根据截取帮助文件中描述,仅添加了块表外的5表记录id + ///xrefSymbolIds可能包含以下符号表记录类型的 ObjectId: + ///BlockTableRecord、LayerTableRecord、LinetypeTableRecord、TextStyleTableRecord(如果它不代表形状文件)、RegAppTableRecord和DimStyleTableRecord。 + + //ViewportTable viewport = tr.GetObject(db.ViewportTableId, OpenMode.ForRead) as ViewportTable;//视口表 + //foreach (ObjectId id1 in viewport) + //{ + // ViewportTableRecord viewportr = (ViewportTableRecord)tr.GetObject(id1, OpenMode.ForRead); + // if (viewportr.IsResolved) + // { + // xrefIds1.Add(viewportr.ObjectId); + // } + //} + //ViewTable viewt = tr.GetObject(db.ViewTableId, OpenMode.ForRead) as ViewTable;// 视图表 + //foreach (ObjectId id1 in viewt) + //{ + // ViewTableRecord viewtr = (ViewTableRecord)tr.GetObject(id1, OpenMode.ForRead); + // if (viewtr.IsResolved) + // { + // xrefIds1.Add(viewtr.ObjectId); + // } + //} + //UcsTable ucst = tr.GetObject(db.UcsTableId, OpenMode.ForRead) as UcsTable;// 用户坐标系表 + //foreach (ObjectId id1 in ucst) + //{ + // UcsTableRecord ucstr = (UcsTableRecord)tr.GetObject(id1, OpenMode.ForRead); + // if (ucstr.IsResolved) + // { + // xrefIds1.Add(ucstr.ObjectId); + // } + //} + #endregion + #endregion + } + + if (isNestedIds.Count > 0)//若有嵌套参照被卸载,重载 + { + db.ReloadXrefs(isNestedIds); + } + + #region 此处即为二者结合使用,且顺序非常重要。若交换秩序,则会绑定无效,切勿交换 + db.XBindXrefs(xBindXrefsIds, true);//建议为true + db.BindXrefs(bindXrefsIds, true);//建议为true + #endregion + + isNestedNodeNameDic = isNestedNodeName; + HostApplicationServices.WorkingDatabase = workingDb; + } + /// + /// 清理符号7表(块表,标注样式表,图层表,线型表,文字样式表,视口样式表,注册应用表) + ///注:视图样式表和坐标系表不能这样清理,有异常 + /// + /// 数据库 + /// 无返回值 + public static void Purge(Database db) + { + ObjectIdCollection ids; + ObjectIdCollection ids1; + ObjectIdCollection ids2; + ObjectIdCollection ids3; + ObjectIdCollection ids4; + ObjectIdCollection ids5; + //ObjectIdCollection ids6; + //ObjectIdCollection ids7; + ObjectIdCollection ids8; + using (Transaction tr = db.TransactionManager.StartTransaction()) + { + //块表 + BlockTable blockt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; + //标注样式表1 + DimStyleTable dimt = tr.GetObject(db.DimStyleTableId, OpenMode.ForRead) as DimStyleTable; + //图层表2 + LayerTable layert = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable; + //线型表3 + LinetypeTable linetypet = tr.GetObject(db.LinetypeTableId, OpenMode.ForRead) as LinetypeTable; + //文字样式4 + TextStyleTable textstylet = tr.GetObject(db.TextStyleTableId, OpenMode.ForRead) as TextStyleTable; + //视口样式表5 + ViewportTable viewport = tr.GetObject(db.ViewportTableId, OpenMode.ForRead) as ViewportTable; + //注册应用表8 + RegAppTable regappt = tr.GetObject(db.RegAppTableId, OpenMode.ForRead) as RegAppTable; + + #region 开始清理 + do + { + ids = new ObjectIdCollection(blockt.Cast().ToArray()); + db.Purge(ids); + if (ids != null) + { + foreach (ObjectId id in ids) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + ids1 = new ObjectIdCollection(dimt.Cast().ToArray()); + db.Purge(ids1); + if (ids1 != null) + { + foreach (ObjectId id in ids1) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + ids2 = new ObjectIdCollection(layert.Cast().ToArray()); + db.Purge(ids2); + if (ids2 != null) + { + foreach (ObjectId id in ids2) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + ids3 = new ObjectIdCollection(linetypet.Cast().ToArray()); + db.Purge(ids3); + if (ids3 != null) + { + foreach (ObjectId id in ids3) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + ids4 = new ObjectIdCollection(textstylet.Cast().ToArray()); + db.Purge(ids4); + if (ids4 != null) + { + foreach (ObjectId id in ids4) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + ids5 = new ObjectIdCollection(viewport.Cast().ToArray()); + db.Purge(ids5); + if (ids5 != null) + { + foreach (ObjectId id in ids5) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + #region 经测试视图样式表和坐标系表不能这样清理,不然有异常 + ////视图样式表6 + //ViewTable viewt = tr.GetObject(db.ViewTableId, OpenMode.ForRead) as ViewTable; + //ids6 = new ObjectIdCollection(viewt.Cast().ToArray()); + //db.Purge(ids6); + //foreach (ObjectId id in ids6) + //{ + // ViewTableRecord btr6 = (ViewTableRecord)tr.GetObject(id, OpenMode.ForWrite); + // btr6.Erase(); + //} + ////坐标系表7 + //UcsTable ucst = tr.GetObject(db.UcsTableId, OpenMode.ForRead) as UcsTable; + //ids7 = new ObjectIdCollection(ucst.Cast().ToArray()); + //db.Purge(ids7); + //foreach (ObjectId id in ids7) + //{ + // UcsTableRecord btr7 = (UcsTableRecord)tr.GetObject(id, OpenMode.ForWrite); + // btr7.Erase(); + //} + #endregion + ids8 = new ObjectIdCollection(regappt.Cast().ToArray()); + db.Purge(ids8); + if (ids8 != null) + { + foreach (ObjectId id in ids8) + { + tr.GetObject(id, OpenMode.ForWrite).Erase(); + } + } + } while (ids.Count > 0 || ids1.Count > 0 || ids2.Count > 0 || ids3.Count > 0 || ids4.Count > 0 || ids5.Count > 0 || ids8.Count > 0); + #endregion + + tr.Commit();//提交事务 + } + } +} \ No newline at end of file