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