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

Editor.SelectAll() to get selection of object IDs not on locked layers

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
mononull
6590 Views, 12 Replies

Editor.SelectAll() to get selection of object IDs not on locked layers

I'm trying to get the Editor class to select all entities in model space not on locked layers, and despite the documentation stating "Selects all objects in the current space in which are not locked or frozen."....it will always return the object IDs from all layers regardless of if they are locked, frozen, or even turned off.  I need it to return a selection set without entities on locked layers.  For most of my classes I am using TypedValue to define the entities I want to filter and then creating a SelectionFilter to pass as an argument to Editor.SelectAll(SelectionFilter).  Since SelectAll is selecting all entities regardless of the layer state, is it possible to create a TypedValue to use as a filter for the selection?  Again, my end goal is to select all entities of certain types on only unlocked layers.

 

Here is what I'm doing now.  Would be great if SelectAll actually ignored locked layers or if I could just add a new TypedValue to get entities on only unlocked layers.  Any help is appreciated.

TypedValue[] tvArr = new TypedValue[]
{
    new TypedValue(-4, "<OR")
    new TypedValue(0, "LINE")
    new TypedValue(0, "LWPOLYLINE")
    new TypedValue(0, "POLYLINE")
    new TypedValue(0, "SPLINE")
    new TypedValue(-4, "OR>")
}

PromptSelectionResult psr 
     = editor.SelectAll(new SelectionFilter(tvArr));

ObjectId[] objectIdArr = psr.Value.GetObjectIds();

 


EDIT:  I can create a list of all objects and then open each one for read to see if the layer it is on is locked, but that seems ridiculous I should have to include all the locked and unlocked objects in the same list and then check the layer state after the list is already made.  It works, but ideally this is not the way it should be done.  It's not very efficient.  If I don't want objects on locked layers I should disclude them before the list is finalized.

12 REPLIES 12
Message 2 of 13
BlackBox_
in reply to: mononull

I suspect you'd need to P/Invoke acedSSGet() using "_:L", as is done in LISP with (ssget "_:L"), or simply iterate the BlockTableRecord, and filter out DBObjects on locked layers.

 

HTH



"How we think determines what we do, and what we do determines what we get."

Message 3 of 13
_gile
in reply to: mononull

Hi,

 

You can use an event handler for the Editor.SelectionAdded event:

 

        [CommandMethod("TEST")]
        public void SelectionTest()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            TypedValue[] filter = 
new TypedValue[1] { new TypedValue(0, "LINE,LWPOLYLINE,POLYLINE,SPLINE") }; ed.SelectionAdded += ed_SelectionAdded; PromptSelectionResult psr = ed.SelectAll(new SelectionFilter(filter)); ed.SelectionAdded -= ed_SelectionAdded; if (psr.Status == PromptStatus.OK) ed.SetImpliedSelection(psr.Value); } private void ed_SelectionAdded(object sender, SelectionAddedEventArgs e) { Database db = HostApplicationServices.WorkingDatabase; using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead); ObjectId[] ids = e.AddedObjects.GetObjectIds(); for (int i = 0; i < ids.Length; i++) { Entity ent = (Entity)tr.GetObject(ids[i], OpenMode.ForRead); LayerTableRecord ltr =
(LayerTableRecord)tr.GetObject(lt[ent.Layer], OpenMode.ForRead); if (ltr.IsLocked) e.Remove(i); } tr.Commit(); } }

 

Another way, using a custom system variable is shown here:

http://www.theswamp.org/index.php?topic=40774.msg460479#msg460479



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 13
mononull
in reply to: _gile

Thanks Gile.  Using the event handler appears to still need to loop though the objectIds after the list is already defined.  I have a method of doing that now without the event handler.

Is there another way to get a selection set filtering out the locked layers...like a .NET equivalent to ssget "_:L" the other member posted?  I don't want the user to have to make the selection manually.  I also don't feel like it's necessary to have to create my own crossing window, or the like, with editor.GetSelection.  That's why I was originally using editor.SelectAll.  I might use the event handler or what I already wrote for now, so thanks.  But if anyone has a better way to get a selection set of specific object types on unlocked layers I'd love to hear it.

Message 5 of 13
_gile
in reply to: mononull

Hi,

 

By my side I don't know any other way to filter out objects on locked layers when using Editor.SelectAll() method.

The .NET equivalent for the LISP (ssget "_:L" ...) would be PromptSelectionOptions.RejectObjectsonLockedLayers which is not available with Editor.SelectAll() as with LISP the "_:L" option cannot be combinated with the "X" one (SelectAll equivalent).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 13
Alfred.NESWADBA
in reply to: mononull

Hi,

 

>> I have a method of doing that now without the event handler.

And that is ...?

 

One option might be to first scan the LayerTable to get a list of layers which are not locked, and use that list as a filter for .SelectAll

   new TypedValue(8, "LAYERA,LAYERC,LAYERX")

 

HTH, - alfred -

------------------------------------------------------------------------------------
Alfred NESWADBA
ISH-Solutions GmbH / Ingenieur Studio HOLLAUS
www.ish-solutions.at ... blog.ish-solutions.at ... LinkedIn ... CDay 2024
------------------------------------------------------------------------------------

(not an Autodesk consultant)
Message 7 of 13
mononull
in reply to: Alfred.NESWADBA

    >> I have a method of doing that now without the event handler.

    And that is ...?

 

  • Getting a list of everything and then looping through each item to check if it's on a locked layer.  

 

I'll check out promptselectionoptions, but it needs to be independent of user input and selections.  Also, I didn't want to have to get the extents min and max, zoom, and create my own selection window if selectall could do all the work.  Thanks for the feedback.

Message 8 of 13
_gile
in reply to: mononull

Hi,

 

If efficiency is the issue, here's a better implementation of the event handler using:

        // Private field used to pass the locked layer names to the event handler
        private HashSet<string> locked;

        [CommandMethod("TEST1")]
        public void SelectionTest1()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "LINE,LWPOLYLINE,POLYLINE,SPLINE") };

	    // Fill the HashSet with the locked layer names
            this.locked = new HashSet<string>();
            using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                foreach (ObjectId id in lt)
                {
                    LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    if (ltr.IsLocked)
                        this.locked.Add(ltr.Name);
                }
            }
// Temporary register the event handler during the selection ed.SelectionAdded += ed_SelectionAdded; PromptSelectionResult psr = ed.SelectAll(new SelectionFilter(filter)); ed.SelectionAdded -= ed_SelectionAdded; if (psr.Status == PromptStatus.OK) ed.SetImpliedSelection(psr.Value); } // The event handler uses the HashSet to check if the entity layer is locked private void ed_SelectionAdded(object sender, SelectionAddedEventArgs e) { Database db = HostApplicationServices.WorkingDatabase; using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { ObjectId[] ids = e.AddedObjects.GetObjectIds(); for (int i = 0; i < ids.Length; i++) { Entity ent = (Entity)tr.GetObject(ids[i], OpenMode.ForRead); if (this.locked.Contains(ent.Layer)) e.Remove(i); } tr.Commit(); } }

 

Here's an example of the way purposed by Alfred (selection filter with the unlocked layer names)

        [CommandMethod("TEST2")]
        public void SelectionTest2()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            // Get all unlocked layaer names
            List<string> unlocked = new List<string>();
            using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
                foreach (ObjectId id in lt)
                {
                    LayerTableRecord ltr = (LayerTableRecord)tr.GetObject(id, OpenMode.ForRead);
                    if (!ltr.IsLocked)
                        unlocked.Add(ltr.Name);
                }
            }

            // Build a selection filter
            TypedValue[] filter = new TypedValue[2]{ 
                new TypedValue(0, "LINE,LWPOLYLINE,POLYLINE,SPLINE"),
                new TypedValue(8, string.Join(",", GetUnlockedLayers(db))) 
            };

            PromptSelectionResult psr = ed.SelectAll(new SelectionFilter(filter));
            if (psr.Status == PromptStatus.OK)
                ed.SetImpliedSelection(psr.Value);
        }

 

I'm not certain the second one is more efficient than the first one, internally each entity have to be opened to use the layer part of the selection filter...

:

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 13
Alexander.Rivilis
in reply to: _gile

Hi, Gilles!

What about layer name has dot or comma? Smiley Happy

1) Some symbols have to be quoted in this string.

2) I'm not sure that the length of string is unlimited. Moreover, as far as I remember, the length of the string should not be more than 255.

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

Message 10 of 13

Hi,

 

>> What about layer name has dot or comma?

How do you create layer with comma in the layername? Comma's are not allowed within layernames. Or have you found a way to include a comma I don't know?

 

>> the length of the string should not be more than 255

I have used a list of blocknames with commas and a length > 2000char for filtering .. always worked. So I guess that will work with layernames too.

 

- alfred -

------------------------------------------------------------------------------------
Alfred NESWADBA
ISH-Solutions GmbH / Ingenieur Studio HOLLAUS
www.ish-solutions.at ... blog.ish-solutions.at ... LinkedIn ... CDay 2024
------------------------------------------------------------------------------------

(not an Autodesk consultant)
Message 11 of 13


@Alfred.NESWADBA wrote:

How do you create layer with comma in the layername? Comma's are not allowed within layernames. Or have you found a way to include a comma I don't know?



Ok! Smiley Wink Comma not allowed, but  "#", "$", ".", "@", "[", "]"  are allowed (wild-card characters):


 

 


@Alfred.NESWADBA wrote:
I have used a list of blocknames with commas and a length > 2000char for filtering .. always worked. So I guess that will work with layernames too.

EXTNAMES

Maximum length of dictionary key names

Length of dictionary key names

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

Message 12 of 13

Hi Alexander,

 

I think I misunderstand things now ...

 

When I do filtering with TypedValue(0,"LAYER1,LAYER2,LAYER3,LAYER4") ... none of the single layernames has more than 255 characters, but as a filterstring in can contain more than 255 characters as far as I know.

So I can collect layernames to one comma-delimited string that is longer than 255 and use it for filtering (as each single layername has less than 255 chars).

And the filtervalue isnot a key-string and does not depend on EXTNAMES as these only specify one single name, not a list of names as a filter string.

 

Am I wrong or did I misunderstand anything?

 

- alfred -

------------------------------------------------------------------------------------
Alfred NESWADBA
ISH-Solutions GmbH / Ingenieur Studio HOLLAUS
www.ish-solutions.at ... blog.ish-solutions.at ... LinkedIn ... CDay 2024
------------------------------------------------------------------------------------

(not an Autodesk consultant)
Message 13 of 13


alfred.neswadba wrote:

...Am I wrong or did I misunderstand anything?...


I think only Autodesk guys can talk you wrong or not. But I'd like next type of filter:

 

TypedValue[] tvArr = new TypedValue[]
{
    new TypedValue(0, "LINE,LWPOLYLINE,POLYLINE,SPLINE")
    new TypedValue(-4, "<OR")
         new TypedValue(8, "LAYER_1")    
         // ... new TypedValue(8, "LAYER_I")
         new TypedValue(8, "LAYER_N")            
    new TypedValue(-4, "OR>")
}

 

Also if such "LAYER_I" has wild-cards character(s) every character have to be escaped with "`".

 

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

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

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report