zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

CAD.NET中使用XBindXrefs、BindXrefs双重绑定参照的探讨

2023-03-31 10:59:29 时间

 

CAD.NET中使用XBindXrefs、BindXrefs双重绑定参照的探讨

/* CAD2023在线帮助链接 https://help.autodesk.com/view/OARX/2023/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_DatabaseServices_Database_XBindXrefs_ObjectIdCollection__MarshalAsUnmanagedType_U1__bool

* (注:本文仅为自己在实际工作中遇到的问题,所找到的一种解决方案,仅供参考、学习使用。若有不足处,欢迎在评论区留言纠正)
* 一、CAD原BindXrefs方法可直接对外部参照BlockTable的id集合绑定,当使用其绑定xrNode.BlockTableRecordId的集合或btr.ObjectId的集合时,往往会出现无法意料的异常,如eInvalidInput、eNullObjectId、eWrongObjectType
* 或各种图层复原等,导致外部参照不能完全绑定,从而达不到图纸的绑定期望。
*
* 二、例如本人遇到的外部参照绑定后图层复原问题、绑定不彻底问题,它俩并不是每次绑定都会出现,而是不一样的图纸,随机发生,只要一出现,原图纸无论怎样处理,再绑定也不能消除异常,即这些问题具有不可预测性。
* 怎样来处理诸如以上描述的问题,一直是棘手的事,也曾通过微软bing、CAD二次开发群等方式搜索、咨询XBindXrefs方法使用相关资料,未找到合理的解决方案。
*
* 三、根据CAD在线帮助文件对XBindXrefs方法描述“The ObjectIds in xrefSymbolIds must all be from the working database and they must all be from resolved xrefs”中发现,需要转换数据库后,再对参照符号表记录id
* 集合绑定。且根据该方法对第一个参数的描述“Input collection of ObjectIds of SymbolTableRecord objects to be bound”,注意到应正确使用XBindXrefs和BindXrefs的顺序。结合“xrefSymbolIds may contain ObjectIds
* for the following symbol table record types: BlockTableRecord, LayerTableRecord, LinetypeTableRecord, TextStyleTableRecord (if it does not represent a shape file),RegAppTableRecord, and DimStyleTableRecord
* 的描述,其中虽含块表记录,经实测,CAD原XBindXrefs方法仅可对图层表记录、线性表记录、文字样式表记录、注册程序表记录、标注样式表记录进行绑定,除对符号表中的用户坐标系表记录、视口表记录、视图表记录是不能绑定外,
* 块表记录却也不能绑定,否则会出现eWrongObjectType异常。
*
* 四、最后经本人实际测试,得出CAD原生XBindXrefs和BindXrefs的结合使用可解决上述大部分异常问题的方式和注意事项,整理如下:
* 1)结合使用须前置的条件:数据库转换,利用WorkingDatabase;
* 2)使用顺序:先XBindXrefs,再BindXrefs;
* 3)关于XBindXrefs可绑定的5个符号表记录累加绑定效果:
*      a、单选XBindXrefs绑定图层表记录,可以解决绝大部分图纸的绑定(本人暂未遇到不能绑定的情况,本选项为“无敌绑定”项)。
*      b、在选用a项绑定时,可能遇到的情况是,如属性文字偏移(本人遇到),很少部分图纸会出现,解决方法是选XBindXrefs绑定图层表记录、文字样式表记录即可。
*      c、除选用a项绑定,若单个单个累加其他剩下4个符号表记录,大部分图纸能正常绑定,少数图纸会出现eWrongObjectType异常,建议根据所需动态选择绑定的符号表记录。
*      d、除选用a项绑定,其他4个符号表记录,一一单选绑定,本人未进行测试,所需者可根据自身要求测试绑定效果。
*
* 五、附本人测试成功的封装代码。该文为本人第一原创,如有引用或转载本文,请标识出处。QQ1039574776。
*/

using Autodesk.AutoCAD.DatabaseServices;
using System.Collections.Generic;
using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace Oncet.CAD
{
    public static class XrefEx
    {
        /// <summary>
        /// XBindXrefs、BindXrefs双重绑定参照。增加绑定符号表累计的选择;增加储存嵌套参照被卸载的字典ref方式
        /// </summary>
        /// <param name="db">数据库</param>
        /// <param name="symbolTableRecordNum">累计要绑定的符号表数量,默认为0。最小为0,最大为4。具体【0为"图层表",1为"文字样式表",2为"线型表",3为"注册应用程序表",4为"标注样式表"】</param>
        /// <param name="isNestedNodeNameDic">储存嵌套参照被卸载的字典</param>
        public static void XBindXrefs(Database db, ref Dictionary<Handle, string> isNestedNodeNameDic, int symbolTableRecordNum = 0)
        {
            //数据库转换
            var workingDb = HostApplicationServices.WorkingDatabase;
            HostApplicationServices.WorkingDatabase = db;

            string errorRemark = db.OriginalFileName;//标记可能出错的文件名,在异常时使用;
            Dictionary<Handle, string> isNestedNodeName = isNestedNodeNameDic;
            try
            {
                db.ResolveXrefs(false, false);//解析数据库
                var bindXrefsIds = new ObjectIdCollection();//声明要BindXrefs的集合
                var xBindXrefsIds = new ObjectIdCollection();//声明要XBindXrefs的集合
                ObjectIdCollection isNestedIds = new ObjectIdCollection();//20220815
                using (var tr = db.TransactionManager.StartTransaction())
                {
                    #region MyRegion20220815-批注原块表参照的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 MyRegion20220815补充是否被嵌套卸载的处理
                    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);//拆离已经卸载的非嵌套文件
                                }
                                if (xrNode.IsNested)//若为嵌套参照
                                {
                                    isNestedIds.Add(deTachId);
                                    isNestedNodeName.Add(deTachId.Handle, xrNode.Name);//有嵌套参照,添加关键信息进字典,以传出方法供绑定后删除处理
                                }
                            }
                        }
                        if (xrNode.XrefStatus == XrefStatus.Unreferenced)//若文件未参照
                        {
                            db.DetachXref(xrNode.BlockTableRecordId);//拆离未参照的文件
                        }
                        #region MyRegion使用此方法添加的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 MyRegion20220814添加XBindXrefs符号表记录id。根据symbolTableRecordNum值范围0~4动态控制5个符号表记录累加绑定需求
                    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 >= 3)
                    {
                        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 >= 2)
                    {
                        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 MyRegion20220814起初测试是将9大符号表记录均加入的,但经实测不行。所以根据截取帮助文件中描述,仅添加了块表外的5表记录id
                    ///xrefSymbolIds可能包含以下符号表记录类型的 ObjectId:
                    ///BlockTableRecord、LayerTableRecord、LinetypeTableRecord、TextStyleTableRecord(如果它不代表形状文件)、RegAppTableRecord和DimStyleTableRecord。
                    ///20220814

                    //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 MyRegion20220814此处即为二者结合使用,且顺序非常重要。若交换秩序,则会绑定无效,切勿交换!!!
                db.XBindXrefs(xBindXrefsIds, true);//20220814建议为true
                db.BindXrefs(bindXrefsIds, true);//20220814建议为true
                #endregion
            }
            catch (System.Exception ex)
            {
                throw new System.Exception(ex.Message);
                //AcCoreAp.ShowAlertDialog("Error: " + ex.Message); 
            }
            finally
            {
                isNestedNodeNameDic = isNestedNodeName;//20220815 
                HostApplicationServices.WorkingDatabase = workingDb;
            }
        }
    }
}

后续1:

根据Q群ifoxcad(QQ718996771)群友反馈,补充了最简测试代码,具体如下

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.Collections.Generic;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace Oncet.CAD
{
    public class _20220817测试
    {
        [CommandMethod("MyXBindXrefs")]//20220817后台绑定最简测试代码(图纸仅绑定,不做其他处理,如清理、关图层、删除嵌套被卸载的参照等)
        public static void MyXBindXrefs()
        {
            string filePath = @"‪C:主屏幕20220817绑定测试文件.dwg";
            using (var db = new Database(false, true))
            {
                Dictionary<Handle, string> isNestedNodeNameDic = new Dictionary<Handle, string>();//用于后期删除嵌套被卸载的参照
                db.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndAllShare, false, null);
                XrefEx.XBindXrefs(db, ref isNestedNodeNameDic, 0);//首选项0
                db.SaveAs(filePath, true, db.OriginalFileVersion, db.SecurityParameters);//保存图纸
            }
        }
        [CommandMethod("MyXBindXrefs1")]//20220817前台绑定最简测试代码(图纸仅绑定,不做其他处理,如清理、关图层、删除嵌套被卸载的参照等)
        public static void MyXBindXrefs1()
        {
            Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
            Editor ed = Doc.Editor;
            Database acdb = Doc.Database;
            Dictionary<Handle, string> isNestedNodeNameDic = new Dictionary<Handle, string>();//用于后期删除嵌套被卸载的参照
            XrefEx.XBindXrefs(acdb, ref isNestedNodeNameDic, 0);//首选项0
            acdb.SaveAs(Doc.Name, true, acdb.OriginalFileVersion, acdb.SecurityParameters);//保存图纸
        }
    }
}

后续2:

20220820补充更新了代码的2个重载和一个清理方法,也可详gitee仓库链接

/// <summary>
/// 表示累计要绑定符号表类型数量的枚举
/// 最小为0,最大为4
/// 具体【0为"图层表",1为"文字样式表",2为"标注样式表",3为"线型表",4为"注册应用程序表"】
/// 如选择TextStyleTable = 1,则表示累计要绑定图层表和文字样式表,以此类推
/// </summary>
public enum XrefSymTabTypeNum
{
    /// <summary>
    /// 图层表,"无敌绑定"项
    /// </summary>
    LayerTable = 0,
    /// <summary>
    /// 文字样式表
    /// </summary>
    TextStyleTable = 1,
    /// <summary>
    /// 标注样式表
    /// </summary>
    DimStyleTable = 2,
    /// <summary>
    /// 线性表
    /// </summary>
    LinetypeTable = 3,
    /// <summary>
    /// 注册应用程序表
    /// </summary>
    RegAppTable = 4
}

/// <summary>
/// 双重绑定参照扩展类
/// <summary>
public static class XrefEx
{
    /// <summary>
    /// 利用两个原生方法双重绑定参照
    /// 可内部删除被卸载的嵌套参照
    /// 该方法仅用于"无敌绑定"项,其他项有异常eWasOpenForNotify
    /// </summary>
    /// <param name="db">数据库</param>
    /// <param name="isEaseNested">询问是否删除被卸载的嵌套参照,默认为true
    /// 主要用于处理要绑定图纸中存在嵌套参照被卸载的情况
    /// 若为false,则嵌套参照将被重载绑定后保留在图纸中</param>
    /// <returns>无返回值</returns>
    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<string>();//要处理的嵌套参照名称列表
        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 != null && isNestedNodeNameList.Count > 0)
                {
                    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;//数据库转换
    }
    /// <summary>
    /// 利用两个原生方法双重绑定参照
    /// 1.增加绑定符号表累计的选择,LayerTable=0时,即单选图层表为"无敌绑定"项
    /// 2.增加储存被卸载嵌套参照名称及句柄的字典,以ref方式传出方法
    /// 提供外部处理嵌套参照的数据,绑定后若不处理,则将被保留在图纸中
    /// </summary>
    /// <param name="db">数据库</param>
    /// <param name="isNestedNodeNameDic">储存被卸载嵌套参照名称及句柄的字典
    /// 主要用于处理要绑定图纸中存在嵌套参照被卸载的情况</param>
    /// <param name="xrefSymTabTypeNum">累计要绑定的符号表数量,默认为LayerTable=0"无敌绑定"项.最小为0,最大为4
    /// 具体【0为"图层表",1为"文字样式表",2为"标注样式表",3为"线型表",4为"注册应用程序表"】</param>
    /// <returns>无返回值,以ref方式传出被卸载嵌套参照名称及句柄的字典</returns>
    public static void XBindXrefs(Database db, ref Dictionary<Handle, string> isNestedNodeNameDic, XrefSymTabTypeNum xrefSymTabTypeNum = XrefSymTabTypeNum.LayerTable)
    {
        var workingDb = HostApplicationServices.WorkingDatabase;//数据库转换
        HostApplicationServices.WorkingDatabase = db;//数据库转换
        
        db.ResolveXrefs(false, false);//解析数据库

        Dictionary<Handle, string> 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;
    }
    /// <summary>
    /// 清理符号7表(块表,标注样式表,图层表,线型表,文字样式表,视口样式表,注册应用表)
    ///注:视图样式表和坐标系表不能这样清理,有异常
    /// </summary>
    /// <param name="db">数据库</param>
    /// <returns>无返回值</returns>
    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<ObjectId>().ToArray());
                db.Purge(ids);
                if (ids != null)
                {
                    foreach (ObjectId id in ids)
                    {
                        tr.GetObject(id, OpenMode.ForWrite).Erase();
                    }
                }
                ids1 = new ObjectIdCollection(dimt.Cast<ObjectId>().ToArray());
                db.Purge(ids1);
                if (ids1 != null)
                {
                    foreach (ObjectId id in ids1)
                    {
                        tr.GetObject(id, OpenMode.ForWrite).Erase();
                    }
                }
                ids2 = new ObjectIdCollection(layert.Cast<ObjectId>().ToArray());
                db.Purge(ids2);
                if (ids2 != null)
                {
                    foreach (ObjectId id in ids2)
                    {
                        tr.GetObject(id, OpenMode.ForWrite).Erase();
                    }
                }
                ids3 = new ObjectIdCollection(linetypet.Cast<ObjectId>().ToArray());
                db.Purge(ids3);
                if (ids3 != null)
                {
                    foreach (ObjectId id in ids3)
                    {
                        tr.GetObject(id, OpenMode.ForWrite).Erase();
                    }
                }
                ids4 = new ObjectIdCollection(textstylet.Cast<ObjectId>().ToArray());
                db.Purge(ids4);
                if (ids4 != null)
                {
                    foreach (ObjectId id in ids4)
                    {
                        tr.GetObject(id, OpenMode.ForWrite).Erase();
                    }
                }
                ids5 = new ObjectIdCollection(viewport.Cast<ObjectId>().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<ObjectId>().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<ObjectId>().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<ObjectId>().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();//提交事务
        }
    }
} 

后续3:

20220822-关于多开CAD后台批量绑定的bug解释,如下图

情况1:先开CAD被卡死情况

 

情况2:多开CAD同步绑,均能顺利完全绑定

 

未完待续...