Selection Set Filter - Block Name CONTAINS

Selection Set Filter - Block Name CONTAINS

David_Prontnicki
Collaborator Collaborator
5,253 Views
10 Replies
Message 1 of 11

Selection Set Filter - Block Name CONTAINS

David_Prontnicki
Collaborator
Collaborator

I know its possible to set a filter list for a block and its name by doing the following:

 

Dim filterlist As TypedValue() = New TypedValue(1) {}
            filterlist(0) = New TypedValue(0, "INSERT")
            filterlist(1) = New TypedValue(2, "ABC")

 But is it possible to set a filter list by "Contains"? Meaning only select blocks (Dynamic or static) that name contains "-SIGN-". So the block name may be XXXX-SIGN-XXXX-XXX. And it will only allow for the selection of blocks that name contains "-SIGN-".

 

Thank you in advance. 

0 Likes
Accepted solutions (2)
5,254 Views
10 Replies
Replies (10)
Message 2 of 11

_gile
Consultant
Consultant
Accepted solution

Hi,

 

In selction filters, the values of type string honor the wild-card patterns.

new TypedValue(2, "*-SIGN_*");


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 11

David_Prontnicki
Collaborator
Collaborator

@_gile  As always, thank you so much! You are the best! 🙂

0 Likes
Message 4 of 11

David_Prontnicki
Collaborator
Collaborator

@_gile 

 

Hey sorry But it does not seem to be working. I have tried all three below with no luck. It will not select the blocks. (Note some are Dynamic and some are static) But it doesn't select either. It works perfect with the single Typed Value Dim acSelectionFilterAll = New TypedValue() {New TypedValue(0, "INSERT")}

 

 

Dim acPromptSelectionOptionsAll As PromptSelectionOptions = New PromptSelectionOptions()
        Dim acSelectionFilterAll = New SelectionFilter({New TypedValue(0, "INSERT"), New TypedValue(2, "*-SIGN-*")})
        acPromptSelectionOptionsAll.MessageForAdding = "Please Select ALL Traffic Sign Details: "
        acPromptSelectionOptionsAll.MessageForRemoval = "Select a Traffic Sign Detail to remove: "
        Dim acPromptSelectionResultsAll As PromptSelectionResult = acCurrentEditor.GetSelection(acPromptSelectionOptionsAll, acSelectionFilterAll)
Dim acPromptSelectionOptionsAll As PromptSelectionOptions = New PromptSelectionOptions()
        Dim acSelectionFilterAll As TypedValue() = New TypedValue(1) {New TypedValue(0, "INSERT"), New TypedValue(2, "*-SIGN-*")}
        acPromptSelectionOptionsAll.MessageForAdding = "Please Select ALL  Traffic Sign Details: "
        acPromptSelectionOptionsAll.MessageForRemoval = "Select a  Traffic Sign Detail to remove: "
        Dim acPromptSelectionResultsAll As PromptSelectionResult = acCurrentEditor.GetSelection(acPromptSelectionOptionsAll, New SelectionFilter(acSelectionFilterAll))
Dim acPromptSelectionOptionsAll As PromptSelectionOptions = New PromptSelectionOptions()
        Dim acSelectionFilterAll As TypedValue() = New TypedValue(1) {}
        acSelectionFilterAll(0) = New TypedValue(0, "INSERT")
        acSelectionFilterAll(1) = New TypedValue(2, "*-SIGN-*")
        acPromptSelectionOptionsAll.MessageForAdding = "Please Select ALL Traffic Sign Details: "
        acPromptSelectionOptionsAll.MessageForRemoval = "Select a Traffic Sign Detail to remove: "
        Dim acPromptSelectionResultsAll As PromptSelectionResult = acCurrentEditor.GetSelection(acPromptSelectionOptionsAll, New SelectionFilter(acSelectionFilterAll))

 

 

0 Likes
Message 5 of 11

norman.yuan
Mentor
Mentor

Dynamic BlockReference  cannot be selected by your block name filter, because its name is something like "*Uxxxx". If you want to get a SelectionSet to select block references which could be/include dynamic ones, you should avoid using block name filter. Instead, you identify them after the selectionset is returned and you loop through them in following code. 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 6 of 11

_gile
Consultant
Consultant

As @norman.yuan said, you cannot directly filter anonymous blocks (*Uxxx blocks) with a selection filter.

You have to select also all the anoynmous blocks and check for each selected block if the name of its DynamicBlockTableRecord (AKA effective name) matches with your pattern.

 Here's an example:

[CommandMethod("TEST1")]
public static void Test1()
{
    var ed = Application.DocumentManager.MdiActiveDocument.Editor;
    var filter = new SelectionFilter(new[] {
        new TypedValue(0, "INSERT"),
        new TypedValue(2, "`*U*,*-SIGN-*") });
    var psr = ed.GetSelection(filter);
    if (psr.Status == PromptStatus.OK)
    {
        var db = HostApplicationServices.WorkingDatabase;
        using (var tr = db.TransactionManager.StartTransaction())
        {
            var ids = new ObjectIdCollection();
            // filter anonymous blocks
            foreach (var id in psr.Value.GetObjectIds())
            {
                var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                string effectiveName =
                    ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name;
                if (Autodesk.AutoCAD.Internal.Utils.WcMatchEx(effectiveName, "*-SIGN-*", true))
                    ids.Add(id);
            }
            var selectedIds = new ObjectId[ids.Count];
            ids.CopyTo(selectedIds, 0);
            ed.SetImpliedSelection(selectedIds);
            tr.Commit();
        }
    }
}

 

You can also do this 'on the fly' by handling the Editor.SelectionAdded event:

[CommandMethod("TEST2")]
public static void Test2()
{
    var ed = Application.DocumentManager.MdiActiveDocument.Editor;
    var filter = new SelectionFilter(new[] {
        new TypedValue(0, "INSERT"),
        new TypedValue(2, "`*U*,*-SIGN-*") });
    ed.SelectionAdded += SelectionAdded;
    var psr = ed.GetSelection(filter);
    ed.SelectionAdded -= SelectionAdded;
    if (psr.Status == PromptStatus.OK)
        ed.SetImpliedSelection(psr.Value);
}

private static void SelectionAdded(object sender, SelectionAddedEventArgs e)
{
    using (var tr = new OpenCloseTransaction())
    {
        for (int i = 0; i < e.AddedObjects.Count; i++)
        {
            var br = (BlockReference)tr.GetObject(e.AddedObjects[i].ObjectId, OpenMode.ForRead);
            string effectiveName =
                ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name;
            if (!Autodesk.AutoCAD.Internal.Utils.WcMatchEx(effectiveName, "*-SIGN-*", true))
                e.Remove(i);
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 11

David_Prontnicki
Collaborator
Collaborator

@_gile 

 

OK So its sort of working now, it is filtering but it is now bypassing the second prompt. I turned your test1 into a function to return the objectid collection and run a for each on all of them. The problem I have is it now skips the second prompt and leaves the objects selected at the end of the command. Im sure its something simple stupid. 🙂

 

I belive I need to convert the objectID collection to a selection set. Just not sure how to do that.

 

Fucntion:

 

Private Function FilterDetails(ByVal acPromptSelectionResultsAll As PromptSelectionResult)

        Dim ids = New ObjectIdCollection()

        Using acTranaction As Transaction = Active.Database.TransactionManager.StartTransaction()

            For Each id In acPromptSelectionResultsAll.Value.GetObjectIds()

                Dim br = CType(acTranaction.GetObject(id, OpenMode.ForRead), BlockReference)
                Dim effectiveName As String = (CType(acTranaction.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)).Name
                If Autodesk.AutoCAD.Internal.Utils.WcMatchEx(effectiveName, "*-SIGN-*", True) Then ids.Add(id)

            Next

            Dim selectedIds = New ObjectId(ids.Count - 1) {}
            ids.CopyTo(selectedIds, 0)
            acCurrentEditor.SetImpliedSelection(selectedIds)
            acTranaction.Commit()

        End Using

        Return ids

    End Function

 

 

Sub:

 

Public Sub SelectDetails()

        Dim acPromptSelectionOptionsAll As PromptSelectionOptions = New PromptSelectionOptions()
        Dim acSelectionFilterAll = New SelectionFilter({New TypedValue(0, "INSERT"), New TypedValue(2, "`*U*,*-SIGN-*")})
        acPromptSelectionOptionsAll.MessageForAdding = "Please Select ALL Traffic Sign Details: "
        acPromptSelectionOptionsAll.MessageForRemoval = "Select a Traffic Sign Detail to remove: "
        Dim acPromptSelectionResultsAll As PromptSelectionResult = acCurrentEditor.GetSelection(acPromptSelectionOptionsAll, acSelectionFilterAll)

        If acPromptSelectionResultsAll.Status = PromptStatus.OK Then

            Dim acSelectionSetAllFiltered = FilterDetails(acPromptSelectionResultsAll)

            Dim acPromptSelectionOptionsExisting As PromptSelectionOptions = New PromptSelectionOptions()
            Dim acSelectionFilterExisting = New SelectionFilter({New TypedValue(0, "INSERT"), New TypedValue(2, "`*U*,*-SIGN-*")})
            acPromptSelectionOptionsExisting.MessageForAdding = "Please Select the Traffic Sign Details to be Exiting: "
            acPromptSelectionOptionsExisting.MessageForRemoval = "Select a Traffic Sign Detail to remove: "
            Dim acPromptSelectionResultsExisting As PromptSelectionResult = acCurrentEditor.GetSelection(acPromptSelectionOptionsExisting, acSelectionFilterExisting)

            If acPromptSelectionResultsExisting.Status = PromptStatus.OK Then

                Dim acSelectionSetExistingFiltered = FilterDetails(acPromptSelectionResultsExisting)

                CreateDetailLayer("G-DTLS-TRAF-SIGN-EXST", 253, "G04030(253)", "Details: Traffic Sign Details - Existing")
                CreateDetailLayer("G-DTLS-TRAF-SIGN-PROP", 3, "B025(11)", "Details: Traffic Sign Details - Proposed")

                For Each acSelectedObjectId In acSelectionSetAllFiltered

                    If Not IsDBNull(acSelectedObjectId) Then

                        SetDetailState(acSelectedObjectId, "G-DTLS-TRAF-SIGN-PROP")

                    End If

                Next

                For Each acSelectedObjectId In acSelectionSetExistingFiltered

                    If Not IsDBNull(acSelectedObjectId) Then

                        SetDetailState(acSelectedObjectId, "G-DTLS-TRAF-SIGN-EXST")

                    End If

                Next

            Else

                CreateDetailLayer("G-DTLS-TRAF-SIGN-PROP", 3, "B025(11)", "Details: Traffic Sign Details - Proposed")

                For Each acSelectedObject In acSelectionSetAllFiltered

                    If Not IsDBNull(acSelectedObject) Then

                        SetDetailState(acSelectedObject, "G-DTLS-TRAF-SIGN-PROP")

                    End If

                Next

            End If

            FreezeDetailGridLayers()

        End If

        acCurrentEditor.Regen()

    End Sub

 

It appears to be doing the following to all selected:

 

 

For Each acSelectedObjectId In acSelectionSetExistingFiltered

                    If Not IsDBNull(acSelectedObjectId) Then

                        SetDetailState(acSelectedObjectId, "G-DTLS-TRAF-SIGN-EXST")

                    End If

                Next

 

 

0 Likes
Message 8 of 11

_gile
Consultant
Consultant

@David_Prontnicki  a écrit :

I belive I need to convert the objectID collection to a selection set. Just not sure how to do that.


If you absolutely need a selection set you can  create a new one frolm an ObjetcId array using the SelectionSet.FromObjectIds static method.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 9 of 11

David_Prontnicki
Collaborator
Collaborator

@_gile 

I apologize, I do not follow how to achieve that?

 

SelectionSet.FromObjectIds is not an option.

0 Likes
Message 10 of 11

_gile
Consultant
Consultant
Accepted solution

Here's an example:

        [CommandMethod("TEST1")]
        public static void Test1()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            var filter = new SelectionFilter(new[] {
        new TypedValue(0, "INSERT"),
        new TypedValue(2, "`*U*,*-SIGN-*") });
            var psr = ed.GetSelection(filter);
            if (psr.Status == PromptStatus.OK)
            {
                var db = HostApplicationServices.WorkingDatabase;
                using (var tr = db.TransactionManager.StartTransaction())
                {
                    var ids = new ObjectIdCollection();
                    // filter anonymous blocks
                    foreach (var id in psr.Value.GetObjectIds())
                    {
                        var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
                        string effectiveName =
                            ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name;
                        if (Autodesk.AutoCAD.Internal.Utils.WcMatchEx(effectiveName, "*-SIGN-*", true))
                            ids.Add(id);
                    }

                    // convert the ObjectIdCollection into an ObjectId array
                    var selectedIds = new ObjectId[ids.Count];
                    ids.CopyTo(selectedIds, 0);

                    // convert the ObjectId array into a SelectionSet
                    var selectionSet = SelectionSet.FromObjectIds(selectedIds);

                    // grip the selection set
                    ed.SetImpliedSelection(selectionSet);

                    tr.Commit();
                }
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 11

David_Prontnicki
Collaborator
Collaborator

@_gile 

 

Thank you very much, I ended up having the same problem. What I found was if I removed the line,

ed.SetImpliedSelection(selectedIds)

from the function, it worked as it should. That was causing the program to skip the next prompt. 

 

So long story short it is working. Thank you again for all your help!!