/* CAD2023線上幫助鏈接 https://help.autodesk.com/view/OARX/2023/ENU/?guid=OARX-ManagedRefGuide-Autodesk_AutoCAD_DatabaseServices_Database_XBindXrefs_ObjectI ...
* (註:本文僅為自己在實際工作中遇到的問題,所找到的一種解決方案,僅供參考、學習使用。若有不足處,歡迎在評論區留言糾正)
* 一、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個符號表記錄,一一單選綁定,本人未進行測試,所需者可根據自身要求測試綁定效果。
*
* 五、附本人測試成功的封裝代碼。如有引用本文,請標識出處。
*/
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;
}
}
}
}