Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Filter elements by parameter value

16 REPLIES 16
Reply
Message 1 of 17
Anonymous
12036 Views, 16 Replies

Filter elements by parameter value

Hi, I've searched the forums for this but couldn't find a clear answer.

 

I'm trying to select all elements in a filteredelementcollector where a parameter, lets say "house number" equals "12". Any other solution where I'd be able to loop through or list all elements that have this parameter value are welcome too.

 

Any help would be appreciated!

16 REPLIES 16
Message 2 of 17
j.buijs
in reply to: Anonymous

I think you can just do the following:

var collector = new FilteredElementCollector(doc).Where(a => a.LookupParameter("house number").AsString() == "12")

Assuming that the storage type of your parameter is string

Message 3 of 17
Anonymous
in reply to: j.buijs

thanks for your reply! However, I tried using it (also checked wether the parameter was a string just to be sure), but the var collector is null. The message I get when looking at it in the locals is: "The collector does not have a filter applied.  Extraction or iteration of elements is not permitted without a filter."

 

Maybe I did something wrong, should I declare it as a filteredelementcollector instead of a var? Or should that not matter.

Message 4 of 17
j.buijs
in reply to: Anonymous

Yes my mistake. I normally always look for a specific element type when using a collector. Didn't know it didn't work when not doing that.

This code works for me and is how I would do it:

List<FamilyInstance> list = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).Where(a => a.LookupParameter("house number").AsString() == "12").Cast<FamilyInstance>().ToList();

It creates a list of FamilyInstance elements. You can change the type to any desired one. Might be another way to not apply a filter and get all element types in one go though, however I would not recommend that because you never know beforehand which kind of elements may pass the filter if you do.

Message 5 of 17
jeremytammik
in reply to: Anonymous

Dear Amar,

 

Thank you for your query.

 

Many thanks also to Jan for his answer.

 

It uses post-processing in .NET.

 

That means that the initial filtering takes place in Revit, and then all family instances are transferred to .NET to check the parameter value.

 

That causes a huge overhead.

 

The overhead can be eliminated by using a parameter filter instead, that checks for the parameter value directly in Revit, before transferring any data to .NET.

 

If you don't care, Jan's solution is fine, of course.

 

Here are some examples of using parameter filters:

 

 

The Building Code provides many more.

 

I hope this helps.

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 6 of 17
j.buijs
in reply to: jeremytammik

Hmm now I'm in doubt about whether or not I should rewrite the collecters in all my own addins to remove that overhead myself...

Some commands that take a long time might actually benefit from that if it's a big difference.

Most commands are nearly instant though so I don't think it would matter in that case.

 

Thanks for the insight Jeremy, as always, very helpful! 🙂

 

Cheers,

 

Jan

Message 7 of 17
jeremytammik
in reply to: j.buijs

Dear Jan,

 

Thank you for your appreciation and very glad to hear you find it useful.

 

Years ago, I benchmarked that stuff and found that moving from .NET post-processing to a parameter filter will save at least 50% overhead:

 

http://thebuildingcoder.typepad.com/blog/2010/04/collector-benchmark.html

 

In a large model, it might be more.

 

Benchmark first, before you do anything!

 

If it works, don't fix it.

 

Please let us know what you find out.

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 8 of 17
jeremytammik
in reply to: Anonymous

Thank you both for the interesting discussion highlighting a couple of important points. 

 

I published it for preservation for posterity, and added yet another hint or two at the end:

 

http://thebuildingcoder.typepad.com/blog/2018/06/forge-tutorials-and-filtering-for-a-parameter-value...

 

Cheers,

 

Jeremy

 

 

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 9 of 17
j.buijs
in reply to: jeremytammik

Thank you very much Jeremy!

 

I updated one of my addins that takes most time to complete.

It's a command for batch copying sheets (and the containing views etc.)

Because of this,  it's much faster! Especially in large documents.

It seems that the FilteredElementCollectors are taking up a lot of time in the overall process and they are much more efficient now that I switched most filters to the build-in Revit API implementation instead of LINQ. 

 

Cheers,

 

Jan

Message 10 of 17
jeremytammik
in reply to: j.buijs

Dear Jan,

 

Congratulations on the great success, and thank you very much for the confirmation.

 

Do you have any further details, or any benchmark results?

 

It sounds as if you just went ahead and implemented it and then judged the speed difference subjectively...

 

What kind of performance improvement did you see?

 

How many elements are being analysed?

 

How large are the models you work with?

 

How much coding work was involved? Lines of code, hours of development work, hours spent debugging?

 

I would love to add this the discussion I already published, to encourage others to take a similar look...

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 11 of 17
j.buijs
in reply to: jeremytammik

Hey Jeremy,

 

Just as a heads-up, I did read your comment but I'm currently very busy with other work.

The way I tested it was just with a plain good old stopwatch, doing exactly the same thing with the different collector filters and it made a noticeable difference.

I do not have the data with me right now. Will update when I get the time later this week or next week. Sorry for that.

 

Cheers,

 

Jan

Message 12 of 17
Anonymous
in reply to: jeremytammik

Hi Jeremy, as Always thanks for your extensive and helpful replies! However, I'm struggling with applying this info to a parameter that is not a builtinparameter. We have a custom parameter, how do I apply that to this code? I think this is what I need, but instead of BuiltInParameter.PHASE_DEMOLISHED It needs to be my custom parameter (which isn't built in I think, or I might misunderstand the concept of BuiltInParameters.) I then need instead of the filternumericGreater a way to see if it equals a certain value.

 

  ParameterValueProvider pvp_Demolished 
    = new ParameterValueProvider( 
      new ElementId( (int) BuiltInParameter
        .PHASE_DEMOLISHED ) );

  FilterNumericGreater fgreater 
    = new FilterNumericGreater();

  FilterElementIdRule IdFilter 
    = new FilterElementIdRule( pvp_Demolished, 
      fgreater, ElementId.InvalidElementId );

  ElementParameterFilter efilter 
    = new ElementParameterFilter( IdFilter );

  FilteredElementCollector elems 
    = new FilteredElementCollector( 
      doc, doc.ActiveView.Id )
        .WherePasses( efilter );

I took this from one from this link you sent me.

 

Thanks in advance!

Message 13 of 17
jeremytammik
in reply to: Anonymous

Dear Amar,

 

Thank you for your appreciation.

 

The solution is easy:

 

Simply replace the ElementId that you are using in the sample code snippet by an element id identifying your custom parameter definition.

 

The sample code snippet uses an element id generated from a built-in parameter.

 

Just as you say, for a custom parameter, no such built-in parameter exists.

 

Read the description of parameters provided in the remarks on the Parameter class:

 

You need to determine the exact source and definition of your custom parameter and find out how to retrieve an element id identifying it to pass into the value provider constructor.

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 14 of 17
jeremytammik
in reply to: jeremytammik

On how to obtain the element id for the custom parameter, here is a quote from the help:

 

"Revit supports both built-in and user-defined parameters. Built-in parameters ship with the application, and they are not stored in Revit documents. User-defined parameters are dynamically created, and they are stored in the documents that use them, wrapped in ParameterElement objects. Different subclasses of ParemeterElement represent different kinds of user-defined parameters. "

 

So, for example, FilteredElementCollection of class ParameterElement would get all user-defined parameters, then a particular one can be searched by name and asked for it's id. Also, at the time of creation of ParameterElement, API user can store the id to use later.

 

Please let us know how you end up solving this, in case it is of interest to others as well.

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 15 of 17
Anonymous
in reply to: jeremytammik

Hi! Pls, help. I am trying to get all families wych belong to the Model category type. I am trying to do it via:

 

			FilteredElementCollector families
				= new FilteredElementCollector( doc )
				.OfClass( typeof( Family ) )
				.Cast<Family>()
				.Where( e => e.FamilyCategory.CategoryType.Equals(CategoryType.Model) );

but I get compile error:

 

error CS0266: Cannot implicitly convert type "System.Collections.Generic.IEnumerable<Autodesk.Revit.DB.FamilyInstance>" to "Autodesk.Revit.DB.FilteredElementCollector"...

I am not so strong in c# & Revit API yet - could you point what I am missing?

 

Revit 2019, ShardDevelop

Message 16 of 17
jeremytammik
in reply to: Anonymous

Please learn more about .NET and LINQ before trying to put together such a complex statement in one single line.

 

Your question has nothing to do with the Revit API. 

 

It is a pure .NET issue.

 

It will probably simplify things for you if you split that statement into several separate smaller ones, and understand their purpose one by one.

 

It looks as if you are casting the results of the filtered element collector to a list of `Family` objects.

 

The result of that cast is an `IEnumerable<Autodesk.Revit.DB.Family>`.

 

That cannot be converted to a `FilteredElementCollector`.

 

Hence an error message.

 

However, I do not see how the statement that you share could cause the exact error message that you show.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 17 of 17
Anonymous
in reply to: jeremytammik

Hi Jeremy.

Thank you very much for your attention, and direction where to learn further.

I was making in hurry a script on previous weak and when got to this problem I solved it by additional check (model category type) while processing the collector. So the question is more about what to learn and my pleasure to get the answer from you.

However, I will try not to forget to place here the solution post upon realizing the reason of my problem.

 

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

Post to forums  

Autodesk Design & Make Report