- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
I am coding an addin that scans a folder of dwg files recursively and checks if the xrefs need to be set to a new location or have to be removed entirely. The end result should be that each dwg file is ready for importing into a Vault (which will not process dwg files if they have unresolved references).
The code I am using here is based on example code from this forum as well as the example projects in the SDK, where they appear to be working as intended.
I am using Application.DocumentManager.Open() to open each of the dwg files in turn (in an autocad session with an empty drawing so I can netload the command and run it. This works as expected, and the first dwg file is opened in the Autocad editor.
I then use this function to get all xrefs in the document that are marked as xref and as unresolved
private List<BlockTableRecord> GetAllXRefs(Document doc, Transaction trans) { List<BlockTableRecord> res = new List<BlockTableRecord>(); if (null == doc || null == trans) return res; try { doc.Database.ResolveXrefs(true, false); // try to resolve any unresolved xrefs in the database XrefGraph graph = doc.Database.GetHostDwgXrefGraph(true); List<BlockTableRecord> xrefs = FindUnresolvedXrefs(graph.RootNode, trans); if (null != xrefs && xrefs.Count > 0) res.AddRange(xrefs); } catch (Exception ex) { MessageBox.Show($"Problem in GetAllXRefs ({ex.Message})"); } return res; }
This function works as well. In my test dwg I have 3 xrefs, one of which is resolved, one of which has been moved to a different folder and one which has been deleted in the folder.
I then go through these blocktablerecords one at a time and use this function to try and find the unresolved xref in any of a given number of paths, and if that fails remove it from the dwg
private bool ProcessUnresolved(BlockTableRecord btr, List<ObjectId> toPurge) { if (btr.XrefStatus != XrefStatus.Unresolved) return false; Messages.Add($"XRef {btr.Name} was unresolved or not found. It was unloaded from the document"); // Unresolved should not be possible, we force a resolve of the xrefs earlier. In theory the state should either be Resolved or FileNotFound string xpath = Cmd.General.FindFilesInFolders(Path.GetFileName(btr.PathName)); if (string.IsNullOrEmpty(xpath) || !File.Exists(xpath)) { // xref could not be resolved Messages.Add($"XRef {btr.Name} could not be found in any of the search locations. It will be removed from the document (including the instances of this xref!)"); toPurge.Add(btr.Id); return true; } // the path was changed btr.UpgradeOpen(); btr.PathName = xpath; btr.DowngradeOpen(); return true; // and this document was modified // there should be a valid path now, but the xref is still unloaded. Assume that Vault will resolve this correctly. // if we need to move the xref location we do that here (and mark the document as modified again) }
xrefs that can be found in a new location have their Pathname changed, the ones that cannot be found are added to the toPurge list.
After processing all unresolved xrefs this way the function is called to handle the xrefs that have to be removed entirely
private bool ProcessPurges(List<ObjectId> toPurge, Document doc, Transaction trans) { if (null == toPurge || toPurge.Count <= 0) return false; if (null == doc || null == trans) return false; Messages.Add($"Purge {toPurge.Count} missing/unresolved xrefs from the database"); // these have to be removed more thoroughly. not just the btr, but also the references to it ObjectIdCollection instances = new ObjectIdCollection(); foreach (ObjectId id in toPurge.Distinct()) { BlockTableRecord btr = trans.GetObject(id, OpenMode.ForWrite) as BlockTableRecord; if (null == btr) continue; instances.Add(id); // we will want to eventually purge the master btr ObjectIdCollection refs = btr.GetBlockReferenceIds(true, true); foreach (ObjectId objId in refs) { DBObject inst = trans.GetObject(objId, OpenMode.ForWrite); inst.Erase(); instances.Add(objId); } // we removed the instances of this record, we can now also remove the reference itself DB.DetachXref(id); btr.Erase(); } doc.Database.Purge(instances); return true; // mark the database as modified }
The code finds any references to the unresolvable xrefs and removes them, then detaches the xref and marks the btr as erased.
At this point when I call GetAllXRefs() again I get only 2 childnodes, both of which are marked as resolved. This suggests that the functions that fixed/removed the xrefs have worked correctly.
However, when I then try to save the modified document with Document.CloseAndSave() it is not saved. if I save it under a different name it is saved, but the unresolved xrefs are still in that copy. If I use Database.SaveAs() instead it again is saved but with the unresolved xrefs still present.
And when I do none of this and leave the document open the GUI xref manager will also show both the original unresolved xrefs as still present in the drawing and both still unresolved.
I must be missing something fairly simple, but it has been a while since I last programmed in the AutoCAD API and that was with C++ so there may be something that does not translate directly to the C# version of the API. Or I just overlooked a detail here.
Solved! Go to Solution.