.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Manage XRef Draworder

18 REPLIES 18
Reply
Message 1 of 19
Brendan_J_Mallon
3396 Views, 18 Replies

Manage XRef Draworder

The Task

I've been tasked with replicating an old VBA tool in C# .NET.

 

Unfortunately all I've got is a screen capture of the form and a description of the purpose, so I don't even have the old VBA as a reference.

 

The VBA tool was used to manage the draw order of XRefs in a drawing.

 

It presented a list of the XRefs with buttons for 'Move To Top', 'Move Up', 'Move Down', 'Move To Bottom'.

 

The XReferences palette doesn't let you do this.  Otherwise you're left with using the DRAWORDER command.

 

If someone's already done this, fine.  I'd still like to understand what's required to code it.

 

So Far 

I can fairly easily get and present a list of the xrefs in a drawing. 

 

I worked out that a TreeView worked well, as it easily allowed drag-n-drop reordering of the files in the list, eliminating the 'Move...' buttons.

 

Each node can also carry the XrefGraphNode object as its Tag, making it possible to get at the objects again.

 

Then all I've done is add 'Update' and 'Close' buttons.

 

I've got the xrefs in the tree, and I'm throwing the XrefGraphNode's 'Database' property at a PropertyGrid I'm using for diagnostics at the moment:

 

Form.jpg

 

So I'm at the point where I'm trying to change the draw order of the Xrefs.  This is where it's 'going to pot'.

 

The Problem(s)

I've had a look at a couple of articles:

They have given me the general idea, without helping with the specifics.

 

I've got two questions:

  1. How can I get the existing draworder of the xrefs so that I can display them in the correct order in the TreeView?
    1. I suspect that the order they're retrieved has more to do with the order they were attached, than their existing draworder.  I'm having trouble proving otherwise.
  2. How do I actually update the draworder for the xrefs?
    1. Here's the code for the 'Update' button cribbed and adapted from the articles above:
private void buttonUpdate_Click(object sender, EventArgs e)
{
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        var objectIDs = new ObjectIdCollection();
        foreach (TreeNode node in treeViewXRefs.Nodes)
        {
            objectIDs.Add(((XrefGraphNode)node.Tag).BlockTableRecordId);
        }

        for (int oi = 0; oi < objectIDs.Count; oi++)
        {
            ObjectId objectID = objectIDs[oi];
            var btr = (BlockTableRecord)t.GetObject(objectID, OpenMode.ForRead);
            var xrColl = new ObjectIdCollection();
            xrColl.Add(objectID);
            var dot = (DrawOrderTable)t.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite);

            if (oi == 0)
                dot.MoveToTop(xrColl);
            else
                dot.MoveBelow(xrColl, objectIDs[oi - 1]);
        }
    }
}

 

When this runs, I get all the way to 'dot.MovetoTop...' and get an 'eInvalidInput' error.

 

All I need is the nudge, or clue that gets me past my blockages, and I think I'm done.  Famous last words!!

18 REPLIES 18
Message 2 of 19
tbrammer
in reply to: Brendan_J_Mallon

First I have to admit that I'm a C++ developer and my C# knowledge is limited. I have worked with the draw order table in C++ so I hope I can help anyway.

I suppose you have N XRefs inserted into the modelspace and you want them to be drawn in a defined order. So you have to get the sortents-table of the modelspace and make sure it contains the objectids of the XRefs in the desired order.

Your code adds the modelspace-ID N times to objectIDs, which doesn't make sense. Instead you need the objectids of the XRefs. So your code should look like this:

 

private void buttonUpdate_Click(object sender, EventArgs e)
{
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
	ObjectId modelspaceID = new ObjectId();
        var objectIDs = new ObjectIdCollection();
        foreach (TreeNode node in treeViewXRefs.Nodes)
        {
	     modelspaceID = ((XrefGraphNode)node.Tag).BlockTableRecordId; //assume all are in modelspace
             objectIDs.Add(((XrefGraphNode)node.Tag).objectId);
        }

        var btr = (BlockTableRecord)t.GetObject(modelspaceID, OpenMode.ForRead);
	var dot = (DrawOrderTable)t.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite);

        for (int oi = 0; oi < objectIDs.Count; oi++)
        {
            ObjectId objectID = objectIDs[oi];
            var xrColl = new ObjectIdCollection();
            xrColl.Add(objectID);
            
            if (oi == 0)
                dot.MoveToTop(xrColl);
            else
                dot.MoveBelow(xrColl, objectIDs[oi - 1]);
        }
} }

 

 


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

Message 3 of 19
Brendan_J_Mallon
in reply to: tbrammer

Thanks for your reply.

 

I had a look at it on Wednesday, but had no joy. 

 

I've been side-tracked since then.

 

First up, your code only ends up with one 'modelspaceID' as the BlockTableRecordId of the last XrefGraphNode in the tree.  Each Xref has it's own BlockTableRecordId, so I'm not sure how that works.

 

Next although the XrefGraphNode doesn't have an 'objectId' property, I understand what you were trying to say.

 

So, I had a look at the properties again.  Along with the BlockTableRecordId, there is an XrefBlockId property in the nested Database property of the XrefGraphNode object.

 

I tried various combinations of gathering these together, but ended up in the same place (eInvalidInput).

 

It's proving frustrating simply because documentation as mostly missing in action and some aspects are completely obtuse.

 

I'm not completely giving up.  I'll have a look at what the DrawOrderTable has in it.

 

Given that I'm providing the require ObjectIdCollection for the MoveToTop and MoveBelow (if I could get that far), I can't see why I get the 'eInvalidInput' error.

Message 4 of 19
tbrammer
in reply to: Brendan_J_Mallon

First I would like to make sure that I understand what you are trying. Let's say you want to display a simple traffic light. You have four DWGs:

  1. Box.dwg contains a  black box
  2. Red.dwg contains a red circle
  3. Yellow.dwg contains a yellow circle 
  4. Green.dwg contains a green circle

You put them together in in Signal.dwg by inserting XREFs to theese four DWGs into the modelspace. Now you have to make sure that the box is drawn first to avoid it obscures the three lights. Is this the scenario we are talking about?

 

Sorry for the XrefGraphNode::objectId()-confusion. I didn't actually know the class XrefGraphNode and thouht this would be the way to get the ObjectId of the XREF. I read the docs in the meantime Smiley WinkXrefGraphNode represents an XREF database (the referenced DWG) and in fact it has no method to retrieve the ObjectId of any actual XREF.

So - providing the scenario described above - I would suggest not to use it at all! Just collect all your XREF ObjectIds within the modelspace with an appropriate iterator, get the sortents table of the modelspace and fill set the draworder of the XREFs according to your needs.


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

Message 5 of 19
Brendan_J_Mallon
in reply to: tbrammer

Yep.  Pretty much the kind of scenario.

 

Of course, something as simple as that would logically be handled at attach timeSmiley Happy, but there will be cases where the draworder gets upset and multiple drawings may need to be shuffled about.  Somewhat tedious using the DRAWORDER command.

 

I did start trying to just get ObjectIDs from the database blocktable.  I'll go back to it.  I did just notice the DrawOrderTableId property of the BlockTable Record.

 

I'll try to expand on this a bit and gather more information.  I might even just return a list of blocktable records, so that I've got access to all the properties.

public static List<ObjectId> GetExternalReferences(Database db)
{
    List<ObjectId> xrefs = new List<ObjectId>();
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        BlockTable bt = t.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;

        foreach (ObjectId id in bt)
        {
            BlockTableRecord btr = id.GetObject(OpenMode.ForRead) as BlockTableRecord;

            if (btr.XrefStatus != XrefStatus.NotAnXref)
                xrefs.Add(id);
        }
        
    }

    return xrefs;
}

 

 

Now... This 'documentation' you're talking about.  Why is it so hard to find?

 

I've known about the AutoCAD .NET Developer's Guide for a fair while.  It's more of a beginners guide though, than a detailed exhaustive reference.

 

Are you referring to content in the ObjectARX download?  I'm not a big fan of the fact that they insist on gathering a pile of information from me before letting me download it.  It's not like I don't get enough propaganda from Autodesk as it is.

 

Or are we talking about some other on-line reference?

 

At least with Microsoft's .NET reference, the vast majority of classes and methods are at least documented on-line even if they don't always carry examples.

 

Other than that I rely heavily on forums for guidance and examples to work from.

Message 6 of 19
tbrammer
in reply to: Brendan_J_Mallon

> Are you referring to content in the ObjectARX download? (...) Or are we talking about some other on-line reference?

 

I refer to the docs in <ARX>\docs\arxmgd.chm. As I said before, I'm C++ developer and rarely use C# and it's docs.

I agree that it is sometimes hard to find the piece of info you're looking for. Besides samples and docs I often use the SNOOP* and REACTORS commands from ArxDbg.arx (from samples\database\ARXDBG) to analyze DWGs. This often gives valuable clues for development.


Thomas Brammer ● Software Developer ● imos AGLinkedIn
If an answer solves your problem please [ACCEPT SOLUTION]. Otherwise explain why not.

Message 7 of 19
Brendan_J_Mallon
in reply to: tbrammer

Thanks for your continued replies.  I accept any tips I can get C++ or C#.

 

I'm a bit surprised that nobody else has weighed in on the topic. You deserve a rest. Smiley Happy

 

Someone has to have reordered XRefs in code before.  I can't be the only one.  Somebody did it in VBA for crying out loud.

 

I wish the person asking me to do this hadn't lost the code.

 

I've got the bones of it, but there's something missing in the detail.

 

I downloaded the ObjectARX package for 2017 and looked in all the files in the doc folder.

 

Yes, I found DrawOrderTable in there (along with XRefGraphNode), but frankly it's a bit sparse on context, detail and examples.

 

There's a spiel on how draworder functions in a DWG, but nothing on how to use the methods.

 

None of the samples exercise the DrawOrderTable, including the 'MoveTo' methods.

 

I thought there might be a clue in the sentence 'DrawOrderTable is the persistent container for draw order information. It resides in the extension dictionary of an associated BlockTableRecord under the key ACAD_SORTENTS.', but I drew a blank when I tried to see what was there.

 

As mentioned before, I've found examples of moving other entities in the draworder, but not XRefs.

 

The example Setting relative draw order of entities using .NET is getting user picked entities and doesn't appear to do anything more than the core DRAWORDER command does.  Maybe with a bit less input.

 

The example Fixing block draw-order in AutoCAD drawings exported by SmartSketch using .NET is pushing wipeouts to the back inside blocks.  Not what I'm trying to do.  Again within user selected entities.

 

So this is what I'm doing now:

 

I gather the IDs of the XRefs :

public static List<ObjectId> GetExternalReferencesAsObjectID(Database db)
{
    
    List<ObjectId> xrefs = new List<ObjectId>();
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        BlockTable bt = t.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;

        foreach (ObjectId id in bt)
        {
            BlockTableRecord btr = id.GetObject(OpenMode.ForRead) as BlockTableRecord;

            if (btr.XrefStatus != XrefStatus.NotAnXref)
                    xrefs.Add(id);
        }
    }

    return xrefs;
}

 

 

Then process them to my TreeView :

void ProcessXRefsToTreeView(TreeView treeView, List<ObjectId> XRefs)
{
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        foreach(ObjectId id in XRefs)
        {
            BlockTableRecord btr = t.GetObject(id, OpenMode.ForRead) as BlockTableRecord;
            TreeNode node = new TreeNode();
            node.Name = node.Text = btr.Name;
            node.Tag = id;
            treeViewXRefs.Nodes.Add(node);
        }
    }
}

 

 

I then have drag-n-drop functionality to reoder the TreeView nodes.

private void treeViewXRefs_ItemDrag(object sender, ItemDragEventArgs e)
{
    DragDropSourceNode = e.Item as TreeNode;
    DoDragDrop(e.Item, DragDropEffects.Move);
}

private void treeViewXRefs_DragEnter(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Move;
}

private void treeViewXRefs_DragDrop(object sender, DragEventArgs e)
{
    Point pos = treeViewXRefs.PointToClient(new Point(e.X, e.Y));
    DragDropTargetNode = treeViewXRefs.GetNodeAt(pos);

    TreeNode nodeCopy = new TreeNode();
    if (DragDropTargetNode != null)
    {
        if (!checkBoxSuppressMessages.Checked)
        {
            MessageBoxButtons mbb = MessageBoxButtons.YesNo;
            string message = string.Format("About to drag drawing '{0}' above drawing '{1}'\n\nIs this OK?", DragDropSourceNode.Name, DragDropTargetNode.Name);
            if (MessageBox.Show(message, "Alert", mbb) == System.Windows.Forms.DialogResult.Yes)
                DragNDropnode(nodeCopy);
        }
        else
            DragNDropnode(nodeCopy);
    }
    else
    {
        if (!checkBoxSuppressMessages.Checked)
        {
            MessageBoxButtons mbb = MessageBoxButtons.YesNo;
            string message = string.Format("Drawing '{0}' will be placed at the bottom of the list.\n\nIs this OK?", DragDropSourceNode.Name);
            if (MessageBox.Show(message, "Alert", mbb) == System.Windows.Forms.DialogResult.Yes)
                DragNDropnode(nodeCopy, true);
        }
        else
            DragNDropnode(nodeCopy, true);
    }

    treeViewXRefs.Invalidate();
    treeViewXRefs.SelectedNode = nodeCopy;
    treeViewXRefs.Focus();

}

void DragNDropnode(TreeNode NodeCopy, bool ToBottom = false)
{
    NodeCopy = (TreeNode)DragDropSourceNode.Clone();
    if (!ToBottom)
        treeViewXRefs.Nodes.Insert(treeViewXRefs.Nodes.IndexOf(DragDropTargetNode), NodeCopy);
    else
        treeViewXRefs.Nodes.Add(NodeCopy);
    DragDropSourceNode.Remove();
}

 

 

Once that's done and the 'Update' button is clicked... well, that's where I'm getting really lost.

 

First I gather the IDs in the order they come out of the rearranged TreeNodes.

private void buttonUpdate_Click(object sender, EventArgs e)
{
    using (Transaction t = db.TransactionManager.StartTransaction())
    {
        var objectIDs = new List<ObjectId>();
        foreach (TreeNode node in treeViewXRefs.Nodes)
            objectIDs.Add((ObjectId)node.Tag);

 

 

Based on Setting relative draw order of entities using .NET, I'm processing the ObjectIds:

        for (int oi = 0; oi < objectIDs.Count; oi++)
        {
            ObjectId xrId = objectIDs[oi];
            var xrColl = new ObjectIdCollection();
            xrColl.Add(xrId);
            BlockTableRecord btr = t.GetObject(xrId, OpenMode.ForRead) as BlockTableRecord;

            DrawOrderTable dot = t.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite) as DrawOrderTable;

            if (oi == 0)
                dot.MoveToTop(xrColl);
            else
                dot.MoveBelow(xrColl, objectIDs[oi - 1]);
        }

        t.Commit();
    }
}

 

 

As soon as I get to 'dot.MoveToTop', I get the 'eInvalidInput' error.

 

So...

  • Is there something wrong with the IDs I'm collecting?
  • Is there something wrong with the ObjectIdCollection I'm creating?
  • Is there something wrong with the DrawOrderTable object I'm getting back?
  • Is it something else altogether?
Message 8 of 19

Hi,

 

My suggestion is to provide a very small code (which can be executed) along with sample drawing along with steps to reproduce the issue.  



Virupaksha Aithal KM
Developer Technical Services
Autodesk Developer Network

Message 9 of 19

Virupaksha,

 

As requested, here's an 'all-in-one' piece of code for what I'm trying to do in the attached XRefDrawOrder.txt file.

 

I've also attached a basic e-transmit of a drawing with some XRefs attached in the XRefDrawOrderTest.zip file.

 

  • I created a standard Visual Studio 2013 'Class Library' project.
  • I added these Autodesk references:
    • accoreMgd.dll
    • acdbmgd.dll
    • acmgd.dll
    • I made sure that 'Copy Local' was set to false.
  • I also added in these standard .NET references:
    • System.Drawing
    • System.Windows.Forms
  • I added the code in the XRefDrawOrder.txt file.
  • Built the solution.
  • Started AutoCAD Map 3D 2015
  • Loaded the dll using NETLOAD
  • Opened the XRefDrawOrderTest.dwg.
    • You might get nags about missing shx files.  These are safe to ignore.
  • Ran the command XRDO.
  • Dragged and dropped files in the list (You can suppress the warnings with the checkbox).
  • Clicked the Update button
    • Got the eInvalidInput error.

I hope that is enough to help someone identify where I'm going wrong.

 

Message 10 of 19

Hi,

 

sorry, but code in Update_Click not clear. You need to provide the entity ID which need to go to top or bottom and call the MoveBelow/MoveToTop using DrawOrderTable of the block which has the entities. Here i feel you need to modify the draw order of xref block references. so you need to use the model space draw order as block references are present in model space. 



Virupaksha Aithal KM
Developer Technical Services
Autodesk Developer Network

Message 11 of 19

OK.  I finally got this one sorted.  A combination of all the sources (thanks tbrammer and Virupaksha particularly) finally cracked it for me.

 

The hard part was getting the correct IDs to pass to the DrawOrderTable methods, not to mention getting the correct DrawOrderTable.

 

In the hope that it helps someone else, I've attached the full code in the 'XRefDrawOrder.txt' file.

 

For the casually interested, I'll pick the eyes out of it as well.

 

I won't go into the supporting methods and classes here, they're all in the attached file.

 

 

Getting the XRefs

 

I've rehashed the process for getting the xrefs.

 

I make sure they're only ModelSpace entities and ensure that they come back in the current draw order.

 

I've commented this one as it takes some explaining.

 

public static List<Entity> GetXRefEntities(Database CurrDBase, Editor CurrED)
{
	// Initialise our return
	List<Entity> result = new List<Entity>();

// Build a selection filter looking for 'INSERT' objects (includes blocks and xrefs) from modelspace (DXF code 67 = 0) TypedValue[] tvs = { new TypedValue(0, "INSERT"), new TypedValue(67, 0) }; SelectionFilter sf = new SelectionFilter(tvs); // Get objects matching the selection filter. PromptSelectionResult psr = CurrED.SelectAll(sf); // Establish a descending integer comparer.  See class in full code. IComparer<int> comparer = new DescendingIntComparer(); /* Apply it to a SortedList storing DrawOrderTable index and entity.    The order the entities are captured in the PromptSelectResult, may not be the order    they appear in the DrawOrderTable.    However the indices of the ObjectIds in the DrawOrderTable are such that highest index is on top.    The SortedList, with the DescendingIntComparer applied, automatically sorts highest DrawOrderTable index to lowest    This ensures that the entities are returned in the correct order.*/ SortedList<intEntity> entsList = new SortedList<intEntity>(comparer); // As long as there is something selected. if (psr.Status == PromptStatus.OK) { // Get the object Ids from the selection. ObjectId[] ids = psr.Value.GetObjectIds(); using (Transaction t = CurrDBase.TransactionManager.StartTransaction()) { // Get the modelspace draw order table. See method in full code. DrawOrderTable dot = Utilities.GetModelSpaceDrawOrderTable(CurrDBase); // Get the ObjectIds of all the entities in the draw order table. byte honor = 0; ObjectIdCollection fdoIDs = dot.GetFullDrawOrder(honor); foreach (ObjectId id in ids) { // Get the block reference of the ID. BlockReference bref = t.GetObject(id, OpenMode.ForRead, falsetrueas BlockReference; // Get the block table record for the block reference. BlockTableRecord btr = bref.BlockTableRecord.GetObject(OpenMode.ForRead) as BlockTableRecord; // If the record is an external reference if (btr.IsFromExternalReference) { // Get the entity for the record. Entity ent = t.GetObject(id, OpenMode.ForRead) as Entity; // Get the index of the entity in the draw order table int entIndex = Utilities.GetDrawTableOrderOfEntity(fdoIDs, ent); // Add the entity and its draw order index to the SortedList entsList.Add(entIndex, ent); } } t.Commit(); } } // For each of the entities in the SortedList foreach (int key in entsList.Keys) // Add the the returned entity list. result.Add(entsList[key]); return result; }

 

 

Adding them to the TreeView

 

To provide reodering, I present the XRef names in a TreeView, enable Drag and Drop and handle the events.

 

public static void ProcessXRefsToTreeView(Database CurrDBase, TreeView TargetTreeView, List<Entity> XRefsEnts)
{
	using (Transaction t = CurrDBase.TransactionManager.StartTransaction())
	{
		foreach (Entity e in XRefsEnts)
		{
			BlockReference bref = t.GetObject(e.ObjectId, OpenMode.ForRead) as BlockReference;
			TreeNode node = new TreeNode();
			node.Name = node.Text = bref.Name;
			node.Tag = e;
			TargetTreeView.Nodes.Add(node);
		}
		t.Commit();
	}
}

 

 

Responding To The Update button

 

private void Update_Click(object sender, EventArgs e)
{
	AS.DocumentLock docLock = doc.LockDocument();
 
	using (Transaction t = db.TransactionManager.StartTransaction())
	{
		DrawOrderTable dot = Utilities.GetModelSpaceDrawOrderTable(db);
 
		List<Entity> ents = new List<Entity>();
		foreach (TreeNode node in XRefListTView.Nodes)
			ents.Add((Entity)node.Tag);
for (int ei = 0; ei < ents.Count; ei++) { Entity ent = ents[ei]; ObjectIdCollection ids = new ObjectIdCollection(); ids.Add(ent.ObjectId); if (ei == 0) dot.MoveToTop(ids); else dot.MoveBelow(ids, ents[ei - 1].ObjectId); } t.Commit(); } Utilities.SendACommand("Regenall "); }

 

 

That all works really well so far.  I'm sure a user will break it at some point.

 

Because there are some people who apply title blocks as XRefs (I don't agree with it, but they do), I could add that functionality, but it begs the question why you'd have more than one XRef in a layout.

Message 12 of 19

Thank you for sharing.

 

I have just one question, by using AutoCAD 2016 it looks like there is no Utilities.GetDrawTableOrderOfEntity property (AutoCAD.Runtime namespace)

What version do you work with.

 

Thanks,

Richard

 

 

Message 13 of 19

Richard,

 

We use Map 3D 2015 at the moment, but that's not the problem. 'Utilities.GetDrawTableOrderOfEntity' is not part of the Autodesk tool set.

 

I suppose it's the problem where everyone loves to have a 'Utilities' class, because there's so few words that can be used for classes that contain 'across the board' methods.  'Utilities' and 'Tools' just about covers it.  So yes you end up having to manage clashes between namespaces/classes with the same name in different namespaces.  Autodesk isn't immune to this.  They have plenty of classes and namespaces that clash with regular framework classes and namespaces.

 

One example is that I've had to use 'using AS = Autodesk.AutoCAD.ApplicationServices'.  If I don't use this, I get a clash between 'Autodesk.AutoCAD.ApplicationServices.Application' and 'System.Windows.Forms.Application'.

 

If you download the 'XRefDrawOrder.txt' file attached to my last post (7th December 2016), you'll find a 'Utilities' class inside the 'XRefDrawOrder' namespace.  This has the 'GetDrawTableOrderOfEntity' method.

 

This txt file is self contained, with only the regular dependencies on the Autodesk managed libraries.  See my post on 7th June 2016 for how I set up a Visual Studio project.

 

Regards

Brendan.

Message 14 of 19


@Brendan_J_Mallon wrote:

Richard,

 

We use Map 3D 2015 at the moment, but that's not the problem. 'Utilities.GetDrawTableOrderOfEntity' is not part of the Autodesk tool set.

 

I suppose it's the problem where everyone loves to have a 'Utilities' class, because there's so few words that can be used for classes that contain 'across the board' methods.  'Utilities' and 'Tools' just about covers it.  So yes you end up having to manage clashes between namespaces/classes with the same name in different namespaces.  Autodesk isn't immune to this.  They have plenty of classes and namespaces that clash with regular framework classes and namespaces.

 

One example is that I've had to use 'using AS = Autodesk.AutoCAD.ApplicationServices'.  If I don't use this, I get a clash between 'Autodesk.AutoCAD.ApplicationServices.Application' and 'System.Windows.Forms.Application'.

 

If you download the 'XRefDrawOrder.txt' file attached to my last post (7th December 2016), you'll find a 'Utilities' class inside the 'XRefDrawOrder' namespace.  This has the 'GetDrawTableOrderOfEntity' method.

 

This txt file is self contained, with only the regular dependencies on the Autodesk managed libraries.  See my post on 7th June 2016 for how I set up a Visual Studio project.

 

public static int GetDrawTableOrderOfEntity(ObjectIdCollection FullDrawOrder, Entity TestEnt)
{
   int fdoCnt = FullDrawOrder.Count;
   ObjectId entId = TestEnt.Id;
   for(int i= 0; i < fdoCnt; i++)
   {
      ObjectId fdoId = FullDrawOrder[i];
      if (fdoId == entId)
         return i;
   }

   return -1;
}

 

Regards

Brendan.


What's the difference between your GetDrawTableOrderOfEntity() method quoted above, and the following?

 


public static int GetDrawTableOrderOfEntity(ObjectIdCollection fullDrawOrder, Entity entity) { return fullDrawOrder.IndexOf(entity.ObjectId); }


 

 

Message 15 of 19


@Brendan_J_Mallon wrote:

 

I've commented this one as it takes some explaining. 

 

Responding To The Update button

 

private void Update_Click(object sender, EventArgs e)
{
	AS.DocumentLock docLock = doc.LockDocument();
 
	using (Transaction t = db.TransactionManager.StartTransaction())
	{
		DrawOrderTable dot = Utilities.GetModelSpaceDrawOrderTable(db);
 
		List<Entity> ents = new List<Entity>();
		foreach (TreeNode node in XRefListTView.Nodes)
			ents.Add((Entity)node.Tag);
for (int ei = 0; ei < ents.Count; ei++) { Entity ent = ents[ei]; ObjectIdCollection ids = new ObjectIdCollection(); ids.Add(ent.ObjectId); if (ei == 0) dot.MoveToTop(ids); else dot.MoveBelow(ids, ents[ei - 1].ObjectId); } t.Commit(); } Utilities.SendACommand("Regenall "); }

 

 

That all works really well so far.  I'm sure a user will break it at some point.

 

 

 


Your code is probably working well, but it might not if there were out-of-process COM/Automation clients trying to connect to AutoCAD, because your code locks the document but never unlocks it.  There are probably other failures that can result from not unlocking the document, but you really don't want to find out about all of them the hard way. The danger of not disposing the DocumentLock is that it will be finalized on a different, concurrently-executing thread by the garbage collector, which could cause AutoCAD to crash. Whether or not that problem manifests depends on what's happening in AutoCAD when the DocumentLock is finalized and its DeleteUnmanagedObject() method tries to unlock the document. IOW, whether AutoCAD crashes or not, is entirely pot luck.

 

See the related docs >here< . Note that the doc at that link contains some inaccuracies, mainly where it says "You use the LockDocument method of the Database object you want to lock.As I'm sure you already know, LockDocument() is not a method of the Database class.

 

 

 

 

 

 

Message 16 of 19

Thank you again.

Message 17 of 19
ahuygen
in reply to: RichardCammeray

Hi,. does anyone have working version of this program?

i would be very happy with that.

 

thanks in advance

Message 18 of 19
Brendan_J_Mallon
in reply to: ahuygen

I can provide a DLL, just not today.

 

If I remember, I'll look at seeing how to get that to you next Monday (3rd Feb).

Message 19 of 19
ahuygen
in reply to: Brendan_J_Mallon

Id appreciate that a lot!

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost