Removing Xref's with c#

Removing Xref's with c#

asdasdfsd2
Contributor Contributor
2,798 Views
12 Replies
Message 1 of 13

Removing Xref's with c#

asdasdfsd2
Contributor
Contributor

Hello,

 

I've been given the task of clearing Xref's from 200+ drawings and plotting them. I am stuck with getting(/finding) the Xref's in the drawings and i have no idea to solve this. Is there anyone that can help with this problem? Help would be greatly appreciated!

 

This is the code i've pieced together. I believe this only returns the drawing itself as an Xref, the actual Xref's remain unseen.

        public void ZkSearchXref()
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var editor = doc.Editor;

            BlockTable blckTbl;
            BlockTableRecord blckTblRcrd;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                    blckTbl = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    blckTblRcrd = tr.GetObject(blckTbl.ObjectId, OpenMode.ForRead) as BlockTableRecord;

                    //db.ResolveXrefs(false,true);
                    XrefGraph XrGraph = db.GetHostDwgXrefGraph(false);
                    GraphNode root = XrGraph.RootNode;

                    GraphNodeCollection gnC = XrGraph.GetOutgoing();
                    editor.WriteMessage("\n" + gnC.Count);

                    //XrefGraphNode child = root.Out(0);
                    //GraphNode child = root.Out(0);
                    //editor.WriteMessage(child.ToString());

                    editor.WriteMessage(root.NumOut.ToString());
                    editor.WriteMessage("\n"+XrGraph.NumNodes.ToString());                    
                    editor.WriteMessage(XrGraph.Node(0).ToString());

                    for (int i = 0; i < XrGraph.NumNodes; i++)
                    {
                        XrefGraphNode xrNode = XrGraph.GetXrefNode(i);
                        editor.WriteMessage("\n" + xrNode.NumIn);
                        editor.WriteMessage("\n" + xrNode.NumOut);

                        //XrefGraphNode xgn = xrNode.GetXrefNode(xrefName);

                        for (int j=0;j<xrNode.NumIn;j++)
                        {

                        }

                        editor.WriteMessage("\n"+"testing");
                        tr.Commit();
                    }
                }
                catch (Autodesk.AutoCAD.Runtime.Exception Ex)
                {
                    Application.ShowAlertDialog("\n" + Ex.Message);
                    tr.Abort();
                }
            } //End TR
        } //End ZkSearchXref

 

 

 

 

 

0 Likes
Accepted solutions (3)
2,799 Views
12 Replies
Replies (12)
Message 2 of 13

_gile
Consultant
Consultant
Accepted solution

Hi,

 

Something like this ?

        public static void DetachAllXrefs()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                foreach (ObjectId id  in blockTable)
                {
                    var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    if (btr.IsFromExternalReference)
                    {
                        db.DetachXref(id);
                    }
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 13

asdasdfsd2
Contributor
Contributor

Yes! Hero! 

 

Thank you very much good sir

0 Likes
Message 4 of 13

asdasdfsd2
Contributor
Contributor

While it works like a charm on a single drawing i'm having dificulty getting this to work in a batch? What am i doing wrong here? I was having dificulties calling commands with "oDoc.Editor.Command()" as well, maybe that's related? 

public void ZkBatchOpenAgain()
        {
            var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var editor = doc.Editor;

            var path = @"pathtofolder";
            String[] dwgfiles = Directory.GetFiles(path);

            for (int i = 0; i < dwgfiles.Length; i++)
            {
                FileInfo myFile = new FileInfo(dwgfiles[i]);
                myFile.IsReadOnly = false;
            }

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                try
                {
                    for (int i = 0; i < dwgfiles.Length; i++)
                    {
                        Document oDoc = AcadApp.DocumentManager.Open(dwgfiles[i], false);

                        //----------------------------------------------------------------------------------------
                        var oDb = oDoc.Database;
                        using (var oTr = oDb.TransactionManager.StartTransaction())
                        {
                            var blockTable = (BlockTable)oTr.GetObject(oDb.BlockTableId, OpenMode.ForRead);
                            foreach (ObjectId id in blockTable)
                            {
                                var btr = (BlockTableRecord)oTr.GetObject(id, OpenMode.ForRead);
                                if (btr.IsFromExternalReference)
                                {
                                    oDb.DetachXref(id);
                                }
                            }
                        }
                        //----------------------------------------------------------------------------------------

                        oDoc.CloseAndSave(oDoc.Name);
                        //oDoc.CloseAndDiscard();
                    }
                    editor.WriteMessage("testing");
                    tr.Commit();
                }
                catch (Autodesk.AutoCAD.Runtime.Exception Ex)
                {
                    Application.ShowAlertDialog("\n" + Ex.Message);
                    tr.Abort();
                }

            }

        }

 

0 Likes
Message 5 of 13

asdasdfsd2
Contributor
Contributor

I also have another approach which doesnt seem to work and this uses "ReadDwgFile" instead of opening the document with the documentmanager. The weird thing here is that the circle is drawn and the file saved so it somewhat works? Can't figure out why the xrefs arent detached either? 

 

 

 

public static void OpenSaveDwgFiles()
        {
            try
            {

                var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
                var db = doc.Database;
                var editor = doc.Editor;

                var path = @"C:\Users\FarridMaagdelijnZKER\OneDrive - ZKER B.V\Bureaublad\TekeningenMap";
                //DirectoryInfo d = new DirectoryInfo(path);
                String[] Files = Directory.GetFiles(path);
                editor.WriteMessage(Files.Length.ToString());
                editor.WriteMessage("\n" + Files[0]);

                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    try
                    {
                        using (Database sourceDb = new Database(false, true))
                        {
                            sourceDb.ReadDwgFile(Files[0], System.IO.FileShare.ReadWrite, true, null);

                            Transaction tr2 = sourceDb.TransactionManager.StartTransaction();
                            using (tr2)
                            {
                                BlockTable bt = tr2.GetObject(sourceDb.BlockTableId, OpenMode.ForRead) as BlockTable;

                                foreach (ObjectId id in bt)
                                {
                                    var btr2 = (BlockTableRecord)tr2.GetObject(id, OpenMode.ForRead);
                                    if (btr2.IsFromExternalReference)
                                    {
                                        db.DetachXref(id);
                                    }
                                }

                                BlockTableRecord btr = tr2.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                                using (Circle crcl = new Circle())
                                {
                                    crcl.Center = new Point3d(1, 1, 0);
                                    crcl.Radius = 5;
                                    btr.AppendEntity(crcl);
                                    tr2.AddNewlyCreatedDBObject(crcl, true);
                                }
                                tr2.Commit();

                                //sourceDb.Save();
                                sourceDb.SaveAs(Files[0], DwgVersion.Current);
                            }
                            //doc.Editor.Command("_.-xref", "D", "*");
                            //doc.Editor.Command("_.-image", "D", "*");
                        }

                    }
                    catch (Autodesk.AutoCAD.Runtime.Exception Ex)
                    {

                    }
                }


                //Application.ShowAlertDialog("All files processed");
            }
            catch (System.Exception ex)
            {
                Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
            }
        }
0 Likes
Message 6 of 13

asdasdfsd2
Contributor
Contributor

Even though i forgot "oTr.Commit();" in the 4th reply the code still doesn't work.

0 Likes
Message 7 of 13

_gile
Consultant
Consultant
Accepted solution

Here's an example of a generic BatchProcess method which takes as arguments the sequence of file names to process and the action to execute on each file (delegate). In this example, the action have to be a method with a single Database argument.

 

        public static void BatchProcess(IEnumerable<string> fileNames, Action<Database> action)
        {
            foreach (string fileName in fileNames)
            {
                try
                {
                    using(var db = new Database(false, true))
                    {
                        db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, null);
                        action(db);
                        db.SaveAs(fileName, DwgVersion.Current);
                    }
                }
                catch (System.Exception ex)
                {
                    var ed = Application.DocumentManager.MdiActiveDocument.Editor; 
                    ed.WriteMessage($"\nError with '{fileName}': {ex.Message}");
                }
            }
        }

 

 

Example of 'action' method to detach all xrefs.

 

        public static void DetachAllXrefs(Database db)
        {
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                foreach (ObjectId id  in blockTable)
                {
                    var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    if (btr.IsFromExternalReference)
                    {
                        db.DetachXref(id);
                    }
                }
                tr.Commit();
            }
        }

 

 

Using example:

 

        [CommandMethod("DETACHXREFS")]
        public static void DetachAllXrefsCmd()
        {
            var fileNames = 
                new System.IO.DirectoryInfo(@"F:\Project\Drawings")
                .GetFiles(" *.dwg")
                .Select(fi => fi.FullName);
            BatchProcess(fileNames, DetachAllXrefs);
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 13

asdasdfsd2
Contributor
Contributor

Thanks a million again!  

0 Likes
Message 9 of 13

asdasdfsd2
Contributor
Contributor

Unfortunately it seems the xrefs are not dettached from the dwg (anymore?!). Yesterday i used the code from your first reply and was able to successfully remove the xrefs from the document. Today i ran the same code and used the same dwg (for test-purposes i did not save so xrefs are still in the document) but the xrefs are not removed anymore? What could be the reason for this? 

It's the same for the code in your last reply which uses delegate, the code runs fine but no xrefs are removed. At this point i realize it may better to supply a dwg. If you don't mind i will send it in a private message for privacy-concerns (since it's an external company we work for)

EDIT: Ok, so apparently i can't use attachments in private messages 

0 Likes
Message 10 of 13

asdasdfsd2
Contributor
Contributor

Ok, here is an example Dwg. Yesterday i used the code from Gile's first reply and was able te remove the xrefs from the drawing. Today i tried again and it wouldn't detach the xrefs anymore. Any help with this would be very much appreciated!  

0 Likes
Message 11 of 13

_gile
Consultant
Consultant

The attached drawing does not contain xref (DWG external reference).

It contains unreferenced raster images (RasterImageDef) which are not xrefs from the point of view of .NET.

These objects are stored in the ACAD_IMAGE_DICT dictionary of the Named Objects Dictionary.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 12 of 13

_gile
Consultant
Consultant
Accepted solution

To purge (i.e. delete all non-referenced) the RasterImageDef of a Database, you can use something like this:

        public static void PurgeRasterImages(Database db)
        {
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
                var imageDict = (DBDictionary)tr.GetObject(NOD.GetAt("ACAD_IMAGE_DICT"), OpenMode.ForRead);
                var imageIds = new ObjectIdCollection();
                foreach (var entry in imageDict)
                {
                    imageIds.Add(entry.Value);
                }
                db.Purge(imageIds);
                foreach (ObjectId id in imageIds)
                {
                    tr.GetObject(id, OpenMode.ForWrite).Erase();
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 13 of 13

asdasdfsd2
Contributor
Contributor

"The attached drawing does not contain xref (DWG external reference).

It contains unreferenced raster images"

 

Noted, thanks again! I ended up removing it by hand with a little help from Lisp but i will surely use this the next time! 

0 Likes