Modify class with ISelectionFilter interface

Modify class with ISelectionFilter interface

EATREVITPOOPCAD
Collaborator Collaborator
2,325 Views
8 Replies
Message 1 of 9

Modify class with ISelectionFilter interface

EATREVITPOOPCAD
Collaborator
Collaborator
    public class addPickFilter : ISelectionFilter
    {
        public bool AllowElement(Element e)
        {
			return (e.Category.Id.IntegerValue.Equals((int)BuiltInCategory.OST_Rooms));
        }

        public bool AllowReference(Reference r, XYZ p)
        {
            return false;
        }
    }

Is there a way to change this class after creating it? I am trying to create a dynamic element selection filter that changes allowed elements to be selected based on user input.  So if the user selects one option it would allow him to select only rooms, or he can choose to be able to select only walls, or he can choose to be able to select rooms and walls. 

 

The only way I can think of doing this is by creating a class with ISelectionFilter interface for every possible outcome....

 

Is there a better way? maybe I could pass an input variable to this class for filter types (=not sure how that works with the interface, because my assumption is that interface has inputs predefined) 

 

Or is there a way to do pass multiple filters to Selection.PickObjects() ?  Something like

IList<Reference> objects = sel.PickObjects(ObjectType.Element, roomPickFilter + wallPickFilter, "Select objects");

 

 

The definition of insanity is doing the same thing over and over again and expecting different results
0 Likes
Accepted solutions (3)
2,326 Views
8 Replies
Replies (8)
Message 2 of 9

AGGilliam
Collaborator
Collaborator
Accepted solution
You can't pass multiple filters into the PickObjects method, but you can create a class similar to LogicalOrFilter to combine multiple filters into one. That's what I do, then just create the individual selection filters and combine them when necessary within the external command.
Message 3 of 9

EATREVITPOOPCAD
Collaborator
Collaborator

Thank you will try it! 

The definition of insanity is doing the same thing over and over again and expecting different results
0 Likes
Message 4 of 9

jshial
Advocate
Advocate
Accepted solution

how about declaring a list of category as property? something like (pseudo code):

 

 

 

 

 

public class addPickFilter : ISelectionFilter
    {
        private List<BuiltInCategory> _categoryMask;
        public List<BuiltInCategory> CategoryMask {get {return this._categoryMask}; 
        set {
             // set a list of categories with value keyword, check null ...
         };}
        
        ctor (List<BuiltInCategory> b_cats){
           // Initialize CategoryMask
        }


public bool AllowElement(Element e)
        {
			// loop through the mask
                         foreach (BuiltInCategory cat in mask)
                         {
                             if (match) return true;  
                         }

                         return  false
;        }

        public bool AllowReference(Reference r, XYZ p)
        {
            return false;
        }
    }

 

 

 

 

Message 5 of 9

EATREVITPOOPCAD
Collaborator
Collaborator

@jshial Thank you for the example! I get the concept but everything falls apart at execution 😅 I will come back to solving this scenario your way when my c# is stronger and have more free time...

 

Here is how I went about this... I found a premade SelFilter class, you can read more about it here: https://thebuildingcoder.typepad.com/blog/2014/12/selfilter-a-powerful-generic-selection-filter-util...

 

SelFilter is a very nifty class, and I believe I kind of ghetto rigged it to do what I need it to do with the whole typeof(int)... In leu of type(int) I really wanted a null there but PickObjects() wouldn't initiate in Revit if one of the filters created with SelFilter.GetElementFilter() had null as its parameter

 

 

 

 

                ISelectionFilter userFilter = SelFilter.GetElementFilter( 
                    addAreas == true ? typeof(Wall) : typeof(int),              
                    addFloors == true ? typeof(Floor) : typeof(int),            
                    addRoofs == true ? typeof(RoofBase) : typeof(int),
                    addRooms == true ? typeof(Room) : typeof(int),
                    addWalls == true ? typeof(Wall) : typeof(int)
                    ); // Ideally 'type(int)' should be 'null' but 'null' doesnt work...

                IList<Reference> listOfObjects = sel.PickObjects(ObjectType.Element, userFilter , "Select objects:");

 

 

 

 

EDIT: ... void is what I was looking for! Now this baby is legit

                ISelectionFilter userFilter = SelFilter.GetElementFilter( 
                    addAreas == true ? typeof(Wall) : typeof(void),              
                    addFloors == true ? typeof(Floor) : typeof(void),            
                    addRoofs == true ? typeof(RoofBase) : typeof(void),
                    addRooms == true ? typeof(Room) : typeof(void),
                    addWalls == true ? typeof(Wall) : typeof(void)
                    );

                IList<Reference> listOfObjects = sel.PickObjects(ObjectType.Element, userFilter , "Select objects:");

 

 

 

 

The definition of insanity is doing the same thing over and over again and expecting different results
Message 6 of 9

jeremy_tammik
Alumni
Alumni

Very minor hint: if your variable `addAreas` is a Boolean, then it has exactly two values: `true` and `false` The return value of comparing it with `true` is also a Boolean with the exact same identical two values. Hence, you can simply skip the `== true` part of the statement. Depending on your taste, that might improve readability. It definitely save a couple of bytes of code text, making it shorter. For me, personally, shorter equals easier to read. Just 2c worth...

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 7 of 9

EATREVITPOOPCAD
Collaborator
Collaborator

thanks @jeremy_tammik , i think removing the ==true is cleaner also

The definition of insanity is doing the same thing over and over again and expecting different results
0 Likes
Message 8 of 9

AGGilliam
Collaborator
Collaborator
Accepted solution

Thanks for sharing your findings, this is a much nicer implementation than what I had in mind. Here's an example of one of the classes I use for selections (there are quite a few):

public class CornerTrimFilter : TBSFilter
    {
        public override bool AllowElement(Element e)
        {
            if (e is FamilyInstance)
            {
                FamilyInstance fi = e as FamilyInstance;
                if (fi.Symbol.FamilyName.Contains("CORNER TRIM"))
                    return true;
                if (fi.Symbol.FamilyName.Contains("STARTER TRIM"))
                    return true;
            }
            return false;
        }
    }

TBSFilter was just a generic class I used as a base class for setting parameters. I went with this method since the majority of our components are Generic Models, so we usually have nothing to compare except for family or type names.

Message 9 of 9

EATREVITPOOPCAD
Collaborator
Collaborator

@AGGilliam I see, this makes more sense now... Thank you sir

The definition of insanity is doing the same thing over and over again and expecting different results