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

AcadSelectionSet.AddItems(AcadBlockReference.Explode())

13 REPLIES 13
Reply
Message 1 of 14
Anonymous
5585 Views, 13 Replies

AcadSelectionSet.AddItems(AcadBlockReference.Explode())

I'm porting a bunch of VBA to VB.Net and came across this. Unchanged,
it fails with "Invalid argument pSelSet in AddItems". My workaround
isn't difficult, just a nuisance for however many times I'll have to
repeat and it seems silly to need to in the first place. I feel like
I'm missing something simple. Is(n't) there a better way?

{code}
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Interop
Imports Autodesk.AutoCAD.Interop.Common
Imports Autodesk.AutoCAD.Runtime

Public Class Class1

'Pick an explodable block before running this.
_
Public Sub AddItemsTest()
Dim Blks As AcadSelectionSet
Dim Dels As AcadSelectionSet
Dim Doc As AcadDocument
Dim Ent As AcadEntity

Doc = Application.AcadApplication.ActiveDocument
Dels = Doc.SelectionSets.Add("Delete")
Blks = Doc.ActiveSelectionSet
For Each Ent In Blks
'Invalid argument pSelSet in AddItems
'Dels.AddItems(Ent.Explode)
'So do the following instead, is there a better way?
Dim Objs() As Object = Ent.Explode
Dim Ents(Objs.Length - 1) As AcadEntity
Objs.CopyTo(Ents, 0)
Dels.AddItems(Ents)
Next
'Do stuff with temp ents to delete
For Each Ent In Dels
Ent.Delete()
Next
Doc.SelectionSets.Item("Delete").Delete()
End Sub

End Class
{/code}

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO
13 REPLIES 13
Message 2 of 14
Anonymous
in reply to: Anonymous

Do you need the entities in a selection set? Can't you just iterate over
the array and " 'Do stuff with temp ents to delete "
--
Bobby C. Jones
http://bobbycjones.spaces.live.com
Message 3 of 14
Anonymous
in reply to: Anonymous

Nope, and yes, of course. But that would mean more change, which I am
trying to avoid as much as possible in the context of initial mass
conversion of nearly 50 working VBA projects to VB.Net. Thank you for
the suggestion though, Bobby. Where I've seen this so far, selection
sets are probably the last thing I would use doing it from scratch or
actually taking time to clean up and optimize. I may go back after I've
got the bigger fish fried...

I suspect the more general problem will come up in other contexts
though, namely anywhere a COM method accepting an AcadEntity() is being
directly fed a System.__ComObject(). I was hoping for someone to reveal
some gem like Option MakeItWork that would just make it work like it did
in VBA... 😉 Or maybe an inline type conversion for an array. I
looked at ConvertAll, but unless I missed something that would add
significantly more code than I already did.

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO



Bobby C. Jones wrote:
> Do you need the entities in a selection set? Can't you just iterate over
> the array and " 'Do stuff with temp ents to delete "
>
Message 4 of 14
Anonymous
in reply to: Anonymous

My experience in converting VBA code is somewhere south of vbnull.
Hopefully someone with more knowledge than me will post something that's
actually useful.
--
Bobby C. Jones
http://bobbycjones.spaces.live.com
Message 5 of 14
Anonymous
in reply to: Anonymous

Someone may have left you with inflated expectations
about the ease of converting VBA to VB.NET.

It's not as simple as some might think. 😉

In this case, you should just use the returned array,
because there's little point to adding the items to a
selection set only to erase them.

More generally, I would lower my expections about
the ease of the conversion process. There's a lot
more to it than just defining a 'ThisDrawing' property.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2009
Supporting AutoCAD 2000 through 2009

http://www.acadxtabs.com

Introducing AcadXTabs 2010:
http://www.caddzone.com/acadxtabs/AcadXTabs2010.htm

Email: string.Format("{0}@{1}.com", "tonyt", "caddzone");


"James Allen" wrote in message
news:6211022@discussion.autodesk.com...
Nope, and yes, of course. But that would mean more change, which I am
trying to avoid as much as possible in the context of initial mass
conversion of nearly 50 working VBA projects to VB.Net. Thank you for
the suggestion though, Bobby. Where I've seen this so far, selection
sets are probably the last thing I would use doing it from scratch or
actually taking time to clean up and optimize. I may go back after I've
got the bigger fish fried...

I suspect the more general problem will come up in other contexts
though, namely anywhere a COM method accepting an AcadEntity() is being
directly fed a System.__ComObject(). I was hoping for someone to reveal
some gem like Option MakeItWork that would just make it work like it did
in VBA... 😉 Or maybe an inline type conversion for an array. I
looked at ConvertAll, but unless I missed something that would add
significantly more code than I already did.

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO



Bobby C. Jones wrote:
> Do you need the entities in a selection set? Can't you just iterate over
> the array and " 'Do stuff with temp ents to delete "
>
Message 6 of 14
Anonymous
in reply to: Anonymous

Don't worry Tony, no such delusions here. That is certainly a potential
pitfall of how it's been presented though.

I only posted about this one of many breaking changes I've seen because
unlike others it seems to have general implications outside the
immediate context.

And agreed, as Bobby rightly suggested, that is what I should do in this
case. I will post back if/when I come across a more sensible example of
the same underlying issue.

Thank you both,

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO



Tony Tanzillo wrote:
> Someone may have left you with inflated expectations
> about the ease of converting VBA to VB.NET.
>
> It's not as simple as some might think. 😉
>
> In this case, you should just use the returned array,
> because there's little point to adding the items to a
> selection set only to erase them.
>
> More generally, I would lower my expections about
> the ease of the conversion process. There's a lot
> more to it than just defining a 'ThisDrawing' property.
>
>
Message 7 of 14
alex_b
in reply to: Anonymous

Hi

I'm trying to do something similar in an out-of-process C# app, and AcadSelectionSet,AddItems() raises an exception.

//perform a WBLOCK on blockName to tempPath
AcadSelectionSet sset = null; sset = AcadDoc.SelectionSets.Add("BlSet"); sset.Clear(); AcadBlocks blocks = AcadDoc.Blocks; AcadBlock bl = null; bl = blocks.Item(blockName);//gets the block definition of input block name int i = bl.Count;//the number of entities in the block definition AcadEntity ent; Object[] objs = new Object[i]; AcadEntity[] ents = new AcadEntity[i]; int j = 0; for (j = 0; j < i; j++)//iterates thru the block definition {   ent = bl.Item(j);//gets one entity   //add it to the array   objs[j] = ent.Copy();//OK } for (j = 0; j < i; j++) {   ents[j] = (AcadEntity)objs[j]; } sset.AddItems(objs);//exception acApp.ActiveDocument.Wblock(tempPath, sset); sset.Delete();

I've tried a number of ways, with and without copying the array and/or the entities, but it never comes out right.

Even when in the debugger I see the entities were added to the selection set, then the Wblock() method raises an exception.

Any tips will be VERY welcome.

Thanks

alex

Message 8 of 14
Hallex
in reply to: alex_b

This one should work:

 

       [CommandMethod("wblocks")]
        public static void WBlocking()
        {
            string tempPath = @"C:\Test\WPART.dwg";
            AcadApplication acApp = new AcadApplicationClass();
            acApp.Documents.Open(@"C:\Test\WorkingDrawing.dwg", Type.Missing, Type.Missing);
            AcadDocument AcadDoc = acApp.ActiveDocument;
            acApp.Visible = true;
            
            AcadSelectionSet sset = null;
            //perform a WBLOCK on blockName to tempPathAcadSelectionSet sset = null;
            sset = AcadDoc.SelectionSets.Add("BlSet");
            List<AcadBlockReference> brefs = new List<AcadBlockReference>();
            AcadBlocks blocks = AcadDoc.Blocks;
            AcadBlock bl = null;
            string blockName = "PART";
            bl = blocks.Item(blockName);//gets the block definition of input block name
            AcadModelSpace AcSpace = AcadDoc.ModelSpace;
           
            //loop through the model space to fill the list of block references
            foreach (AcadEntity acEnt in AcSpace)
            {
                if (acEnt is AcadBlockReference)
                {
                    AcadBlockReference AcBref = acEnt as AcadBlockReference;
                    if (AcBref.EffectiveName == blockName)
                    {
                        brefs.Add(AcBref);
                   
                    }
                }
            }
            // convert list to array of objects
            Object[] objs = brefs.ToArray(); 
            // cast array as single object
            Object pSelSet = (Object)objs;
            sset.AddItems(pSelSet);// select Additems, then click "Go to Definition" to see arguments
            acApp.ActiveDocument.Wblock(tempPath, sset);
            sset.Delete();
            
            AcadDoc.Close(Type.Missing, Type.Missing);
        }

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 9 of 14
alex_b
in reply to: Hallex

Hallex

Thank you for the response.

If I understand your code correctly, it writes to disk all instances of a particular block reference, which is not what I meant.

What I need is to write to disk just the block definition (as in WBLOCK blockName ...)

ANyway, I modified my code as per your suggestion, but I still get an exception on

sset.AddItems(pSelSet);//exception

The exception is:Error HRESULT E_FAIL has been returned from a call to a COM component.

Could you comment on that?

N.B. The code has to be compatible with ACAD 2004. Could this be the problem?

Thanks again

alex

 

Message 10 of 14
Hallex
in reply to: alex_b

To write on disk the block definitions you have use CloneObjects method instead,

see VBA help for more, if I can I will try to write an example about

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 11 of 14
alex_b
in reply to: Hallex

Hallex

I can't seem to find a CloneObjects() method in Interop.

If you mean CopyObjects(), all I could find about it is some examples of its use for copying objects between databases and no documentation (also the examples are in VB, knowledge of which I have less than zero).

I understand that there is a problem copying entities from a block definition.

Maybe the (ugly) solution would be

[insert the block; explode it; add the exploded entities to the selection set; wblock the selection set; erase the exploded entities]

Could you help?

Thanks

alex

Message 12 of 14
Hallex
in reply to: alex_b

I can't test this code on A2004,

just tested them on my A2010, all is Ok here

Try again:

 

       [CommandMethod("copydef")]
       public static void CopyBlockDefToDwg()
       { 
         
           MessageBox.Show("Wait...");
           // change file names to suit:
           string sourcePath = @"C:\Test\WorkingDrawing2.dwg";
           string tempPath = @"C:\Test\atest.dwg";
           AcadApplication acApp = new AcadApplicationClass();
           //open for read only
           acApp.Documents.Open(sourcePath, Type.Missing, Type.Missing);
           AcadDocument AcadDoc = acApp.ActiveDocument;
           acApp.Visible = true;

           AcadBlocks blocks = AcadDoc.Blocks;
           // change block name to suit
           string blockName = "PART";
           AcadBlock bl = blocks.Item(blockName);//gets the block definition of input block name
           // copy blockdefinition to array of AcadObject
           AcadObject[] copy = new AcadObject[1];
           copy[0] = (AcadObject)bl;
           // convert array as single object
           object safe = copy as object;
           //open for read write
           acApp.Documents.Open(tempPath, false, Type.Missing);
           // set source document to be active
           AcadDocument newDoc = acApp.ActiveDocument;
           // prepare arguments for CoptObjects
           object IdPairs = new object();
           // set all arguments as objects
           AcadDoc.CopyObjects(safe, newDoc.Blocks as object, ref IdPairs);
           // close and save destination document
           newDoc.SaveAs(tempPath, Type.Missing, Type.Missing);
           acApp.ActiveDocument = AcadDoc;
           newDoc.Close();
           // close source document without changes
           AcadDoc.Close(Type.Missing, Type.Missing);
           acApp.Quit();
       }

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 13 of 14
alex_b
in reply to: Hallex

Hallex

The method you posted adds the block definition to the Blocks collection.

I needed it to work like the WBLOCK Autocad command, so I had to modify it a little for that (copy the block definition entityes to the new db model space).

There were some issues with parameters too (probably because the Acad 2004 compatibility requirement).

Anyway, your suggestion works great and Thank you.

Here is the final code:

private void createOutDwg(string tempPath, string blockToOutput)
{
  AcadBlocks blocks = aCadDoc.Blocks;
  AcadBlock bl = blocks.Item(blockToOutput);//gets the block definition
  // copy block definition to array of AcadObject
  int i = bl.Count;
  AcadObject[] copy = new AcadObject[i];
  for (int j = 0; j < i; j++)//iterates thru the block definition
  {
    copy[j] = (AcadObject)bl.Item(j); ;//gets one entity
  }
  // convert array as single object
  object safe = copy as object;
  //create new document
  acApp.Documents.Add(Type.Missing);
  //remember it
  AcadDocument newDoc = acApp.ActiveDocument;
  // prepare arguments for CopyObjects
  object IdPairs = new object();
  // set all arguments as objects
  aCadDoc.CopyObjects(safe, newDoc.ModelSpace as object, ref IdPairs);
  //save and close destination document
  newDoc.SaveAs(tempPath, Type.Missing, Type.Missing);
  //make source document active before closing new doc
  acApp.ActiveDocument = aCadDoc;
  newDoc.Close(Type.Missing, Type.Missing);
}

 I still can't understand why we can't just add entities from the block definition to a selection set and the just Wblock() it. Maybe the Autocad people would like to comment on that.

Thank you again.

alex

Message 14 of 14
Hallex
in reply to: alex_b

Glad I could help,

Happy coding,

Cheers Smiley Happy

 

~'J'~

_____________________________________
C6309D9E0751D165D0934D0621DFF27919

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