Author Topic: Bind xref  (Read 12489 times)

0 Members and 1 Guest are viewing this topic.

cadpro

  • Guest
Bind xref
« on: September 06, 2006, 08:41:49 AM »
Hi all,

This is my first post in this site. I would like to know if we can bind xrefs in VB.NET? I tried different ways, and search a lot on this topic, but did not get a solution. This is my last...I would say life saving try...and I'm sure I will get a solution here. Please help.

Thanks

Glenn R

  • Guest
Re: Bind xref
« Reply #1 on: September 06, 2006, 09:46:05 PM »
Ah...a subject I love :D

Quote
I would like to know if we can bind xrefs in VB.NET?

Yep, but it's not native, so to speak. Binding is a lot more complex than people first think.
Some things to ponder:

1. Do you want to bind all or be selective?
2. What happens when you run across an xref that's unloaded/unresolved?

Also, I've found that the XrefGraphNode implementation is flawed.
Code like this:
Code: [Select]
for (int j = 0; j < xrefGraphNode.NumOut; j++) {
XrefGraphNode outgoingNode = xrefGraphNode.Out(j) as XrefGraphNode;
if (outgoingNode != null)
ed.WriteMessage("-->{0}", outgoingNode.Name);
}//for

will fail on the cast even though GraphNode is the base class (supposedly) for XrefGraphNode.

Cheers,
Glenn.

cadpro

  • Guest
Re: Bind xref
« Reply #2 on: September 09, 2006, 03:46:10 AM »
Thanks for the reply and glad to know that it's a subject you love.

Answeres to your questions:

1. I want to bind all xrefs.
2.If the xref is unloaded, be it nested or not, I reload it with a blank drawing from a specified location.

And fortunately or unfortunately, I've used xrefGraphNode to reload unloaded xrefs with blank dwgs, which works fine. Here is the code:

Code: [Select]
      Try
                For I = 0 To XG.NumNodes - 1
                    Dim XGNode As XrefGraphNode = XG.GetXrefNode(I)
                    If XGNode.NumIn = 0 Then GoTo Continue
                    If XGNode.XrefStatus = XrefStatus.Unloaded Then
                        Dim BTR As BlockTableRecord = Trans.GetObject(BT(XGNode.Name), OpenMode.ForWrite)
                        BTR.IsUnloaded = False
                        If BTR.IsResolved = False Then
                            BTR.Database.ResolveXrefs(True, False)
                            BTR.PathName = "C:\$Blank.dwg"
                        End If
                    End If
Continue:
                Next


                Trans.Commit()
            Catch ex As Exception
                MsgBox(ex.ToString)
            Finally
                Trans.Dispose()
            End Try

Thanks

Glenn R

  • Guest
Re: Bind xref
« Reply #3 on: September 09, 2006, 08:58:52 PM »
I thought of blatantly reloading/repathing an xref too, but it could have been deliberate (the unload) so I decided the most sensible thing to do was get the program to complain loudly and stop.

Have a look at the attached image 'XrefDlg'. It's the most complex/convoluted xref nesting scenario I could come up with and is what I use to test all xref related things on.
As far as changing the path as you do, it won't work on nested xrefs as you can only change that in their immediate host file, which in the current drawing is essentially read-only.

You can change it with VBA and maybe .net, but it won't stick if you reopen the drawing. One solution might be to use TonyT's idea and class for temporarily switching the WorkingDatabase to the xref database, then switch back....maybe.

Attached also is a zip file with the relevant drawings from that image so you can test with it.

Try running this code over the attached "xref bind test.dwg":

Code: [Select]
// Define Command "LX"
[CommandMethod("LX")]
static public void ListXrefsCommand() {
// Get a pointer to the active document...
Document doc = acadApp.DocumentManager.MdiActiveDocument;
// From the active document, get a pointer to the doc's dbase...
Database db = doc.Database;
// Get a pointer to the editor...
Editor ed = doc.Editor;

// Get the xref graph for the current dbase...
XrefGraph xrefGraph = db.GetHostDwgXrefGraph(true);
if (xrefGraph.IsEmpty || xrefGraph.NumNodes == 1) {
ed.WriteMessage("\nNo xrefs found.");
return; // No xrefs...
}

for (int i = 0; i < xrefGraph.NumNodes; i++) {
XrefGraphNode xrefGraphNode = xrefGraph.GetXrefNode(i);
if (xrefGraphNode == null) {
ed.WriteMessage("\nError: Failed to get a node on the graph - aborting!");
return;
}
// Is it the root node, which is the current drawing?
// If it IS, then the number of incoming nodes will be 0...
if (xrefGraphNode.NumIn == 0)
continue;
// Continue if it's truly nested...
if (xrefGraphNode.IsNested)
continue;

ed.WriteMessage("\nXref name: {0}", xrefGraphNode.Name);

for (int j = 0; j < xrefGraphNode.NumOut; j++) {
XrefGraphNode outgoingNode = xrefGraphNode.Out(j) as XrefGraphNode;
if (outgoingNode != null)
ed.WriteMessage("-->{0}", outgoingNode.Name);
}//for

}//for

}

Tell me if it lists ALL xrefs.

Also, by looking at the attached image, which xrefs can be bound and which ones can't? I do have a solution for the bind, which I will post up in a bit, but first let's continue this discussion and see what others have to say.

Cheers,
Glenn.

cadpro

  • Guest
Re: Bind xref
« Reply #4 on: September 10, 2006, 02:01:50 AM »
Hi Glenn,
After going through your post, I played around with the drawing "xref bind test.dwg". Yes, it is quite complex.

Quote
As far as changing the path as you do, it won't work on nested xrefs as you can only change that in their immediate host file, which in the current drawing is essentially read-only.

It did work! First I unloaded the xref named "triangle". Then I tried to bind all xrefs manually, but it didn't work. Then I loaded the code that I sent in the last post. Yes, it changed the path of triangle to "C:\$Blank.dwg". Then I could manually bind all xrefs. So this is what I am looking for. After reloading the unloaded xrefs with blank dwg, the drawing should be bound using code.

Oh! One important thing I forgot to mention is, I open the dwg as readonly using code, and my intention is to saveas the dwg to a different location and close the original dwg without saving. All I am trying to do is a batch bind.

Quote
One solution might be to use TonyT's idea and class for temporarily switching the WorkingDatabase to the xref database, then switch back....maybe.

I prefer the xrefs to be untouched.

Thanks



Glenn R

  • Guest
Re: Bind xref
« Reply #5 on: September 10, 2006, 04:29:10 AM »
I should have rephrased what I said about it wouldn't work to re-path then bind. It will work when the drawing is open, but as I mentioned, if you re-open the drawing then the paths will be back the way they are defined in the IMMEDIATE HOST drawing...hence it's only a temporary fix, however in this situation it probably doesn't matter.

Another option you might consider and is the route I went, is if the xref is unloaded, search for it in all the AutoCAD search paths, then reload it. Record the ones you reloaded and once you have succesfully bound, go through and erase all references to it, then delete the block table record.

Cheers,
Glenn.

Glenn R

  • Guest
Re: Bind xref
« Reply #6 on: September 10, 2006, 04:38:58 AM »
This is something I quickly whipped up the other day:

Code: [Select]
[DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi,
   EntryPoint = "?acedXrefBind@@YA?AW4ErrorStatus@Acad@@PBD_N1PAVAcDbDatabase@@@Z")]
extern public static int acedXrefBind(string XrefBlockname, bool bInsertBind, bool bQuiet, IntPtr db);

public tcgsClass( ) {
// Does nothing in this implementation
}

// Define Command "BAX"
[CommandMethod("BAX")]
static public void BindAllXrefsCommand( ) {

Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

// Get the xref graph for the current dbase...
XrefGraph xrefGraph = db.GetHostDwgXrefGraph(true);
if (xrefGraph == null || xrefGraph.IsEmpty || xrefGraph.NumNodes == 1) {
ed.WriteMessage("\nNo xrefs found.");
return; // No xrefs...
}

if (xrefGraph.MarkUnresolvedTrees()) {
ed.WriteMessage("\nError: There are unresolved xrefs - bind aborted!");
return;
}

for (int i = 0; i < xrefGraph.NumNodes; i++) {

XrefGraphNode xrefGraphNode = xrefGraph.GetXrefNode(i);
if (xrefGraphNode == null) {
ed.WriteMessage("\nError: Failed to get a node on the graph - aborting!");
return;
}

// Is it the root node, which is the current drawing?
// If it IS, then the number of incoming nodes will be 0...
if (xrefGraphNode == xrefGraph.HostDrawing)
continue;

// Continue if it's truly nested as we can only bind "true" top level parents...
if (xrefGraphNode.IsNested)
continue;

if (xrefGraphNode.NumIn == 1) {

string xrefName = null;

using (Transaction tr = db.TransactionManager.StartTransaction()) {

BlockTableRecord btr = tr.GetObject(xrefGraphNode.BlockTableRecordId, OpenMode.ForRead, false) as BlockTableRecord;
if (btr == null) {
ed.WriteMessage("\nError: Failed to get xref name - aborting!");
return;
}

xrefName = btr.Name;
}

if (xrefName != null) {

ed.WriteMessage("\nBinding xref {0}...", xrefName);
acedXrefBind(xrefName, false, false, IntPtr.Zero);

}
}

}//for

}

Give that whirl.......

Cheers,
Glenn.

cadpro

  • Guest
Re: Bind xref
« Reply #7 on: September 10, 2006, 09:22:23 AM »

Quote
search for it in all the AutoCAD search paths, then reload it. Record the ones you reloaded and once you have succesfully bound, go through and erase all references to it, then delete the block table record.

I don't think it would be practical to search for the xref file and reload as the users are working on the network drive. Above all, my whole problem is, how do I bind. I don't see a BIND method or acedXrefBind in VB.NET.

Thanks

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bind xref
« Reply #8 on: September 10, 2006, 05:13:14 PM »
Cadpro, there is none .. you'll have to do as Glenn has done for C# ; Import the acedXrefBind
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bind xref
« Reply #9 on: September 10, 2006, 05:18:29 PM »
If you're using AC2007, the EntryPoint and CharSet will be different, something like this :
Quote
    [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode,
       EntryPoint = "?acedXrefBind@@YA?AW4ErrorStatus@Acad@@PB_W_N1PAVAcDbDatabase@@@Z")]
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Bind xref
« Reply #10 on: September 10, 2006, 06:28:02 PM »
Quote
as the users are working on the network drive

Doesn't make squat bit of difference where it is - the trick is knowing what to search and how.

Glenn R

  • Guest
Re: Bind xref
« Reply #11 on: September 10, 2006, 06:35:02 PM »
After all this, you still haven't alluded to how you are handling an unresolved xref ie not found or orphaned...?
Because if you aren't handling them in some way, that will cause a bind to fail outright.

cadpro

  • Guest
Re: Bind xref
« Reply #12 on: September 16, 2006, 05:26:21 AM »
Hi,
I'm exteremly sorry for the delay in reply. I converted the code that Glenn had posted and WOW! it works great. Hats off to you Glenn! But...one very important issue....I am using AutoCAD 2006. So is this version dependant? If so, I'm  :cry: What is the solution to that?

Thanks

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bind xref
« Reply #13 on: September 16, 2006, 05:31:49 AM »
cadpro, how are you handling any unresolved xrefs ?

.. and could you post all the code you're usong so that others may benefit.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bind xref
« Reply #14 on: September 16, 2006, 07:46:51 AM »
....I am using AutoCAD 2006. So is this version dependant? If so, I'm  :cry: What is the solution to that?

Thanks

Did you read Post Reply #9 ?
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Bind xref
« Reply #15 on: September 19, 2006, 05:39:10 AM »
I think you scared him off Kerry   :angel:

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Bind xref
« Reply #16 on: September 19, 2006, 05:50:03 AM »
I seem to do that a lot .. must be time for a demeanor overhaul .. I'd better check the service book.


:lol:
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Glenn R

  • Guest
Re: Bind xref
« Reply #17 on: September 19, 2006, 08:41:23 AM »
I don't think that's necessary Kerry. You summed up my feelings as well. Close of thread me thinks.

cadpro

  • Guest
Re: Bind xref
« Reply #18 on: September 23, 2006, 03:07:00 AM »
Oh guys! sorry for the delay. I was off for a week. I will get back to you soon. Just trying to recall the bind xref code

Glenn R

  • Guest
Re: Bind xref
« Reply #19 on: September 29, 2006, 07:47:31 AM »
You whooooooooo...............

Glenn R

  • Guest
Re: Bind xref
« Reply #20 on: October 13, 2006, 09:33:49 AM »
Quote
I will get back to you soon. Just trying to recall the bind xref code
'Recall'...it was such a 'major' thing:
Quote
This is my last...I would say life saving try

Hello....wannabe...?