Hi
I am trying to filter walls based on "Fire Rating" parameter but it retrieves walls that the rule satisfies plus walls that don't contain that parameter!
so how can it ignore walls that don't contain that parameter!?
ParameterValueProvider provider = new ParameterValueProvider(new ElementId((int)BuiltInParameter.FIRE_RATING));
FilterStringRule rule1 = new FilterStringRule(provider, new FilterStringContains(), @"/", false);
ElementParameterFilter filter1 = new ElementParameterFilter(rule1);
var MyWalls=(new FilteredElementCollector(doc))
.OfCategory(BuiltInCategory.OST_Walls)
.WherePasses(filter1)
.ToElementIds();
Solved! Go to Solution.
Solved by jeremy_tammik. Go to Solution.
Can you please provide a minimal reproducible case for the development team and others to analyse?
https://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
Thank you!
Hi @jeremytammik,
I sent a message to you having the reproducible case attached.
Please let me know when you receive it.
I received the sample model and am looking at it now.
Dear Ameer,
Thank you for your nice clean reproducible case.
I can reproduce the behaviour you describe and find it rather weird as well, so I submitted it to the development team for further analysis.
I logged the issue REVIT-172990 [Parameter filter with FilterStringContains returns false positive] with our development team for this on your behalf as it requires further exploration and possibly a modification to our software. Please make a note of this number for future reference.
You are welcome to request an update on the status of this issue or to provide additional information on it at any time quoting this change request number.
This issue is important to me. What can I do to help?
This issue needs to be assessed by our engineering team and prioritised against all other outstanding change requests. Any information that you can provide to influence this assessment will help. Please provide the following where possible:
This information is extremely important. Our engineering team have limited resources, and so must focus their efforts on the highest impact items. We do understand that this will cause you delays and affect your development planning, and we appreciate your cooperation and patience.
I cleaned up your code and submitted it in the following form as TestFilterStringContains:
public void TestFilterStringContains( Document doc )
{
BuiltInParameter bip = BuiltInParameter.FIRE_RATING;
ElementId pid = new ElementId( bip );
ParameterValueProvider provider
= new ParameterValueProvider( pid );
FilterStringRuleEvaluator evaluator
= new FilterStringContains();
FilterStringRule rule = new FilterStringRule(
provider, evaluator, "/", false );
ElementParameterFilter filter
= new ElementParameterFilter( rule );
var myWalls = new FilteredElementCollector( doc )
.OfCategory( BuiltInCategory.OST_Walls )
.WherePasses( filter );
List<ElementId> false_positive_ids
= new List<ElementId>();
foreach( Element wall in myWalls )
{
Parameter param = wall.get_Parameter( bip );
if( null == param )
{
false_positive_ids.Add( wall.Id );
}
}
string s = string.Join( ", ",
false_positive_ids.Select<ElementId, string>(
id => id.IntegerValue.ToString() ) );
TaskDialog dlg = new TaskDialog( "False Positives" );
dlg.MainInstruction = "False filtered walls ids: ";
dlg.MainContent = s;
dlg.Show();
}
It displays a message like this in your sample model:
You might be able to achieve the desired result by combining the FilterStringContains evaluator with other rules and filters.
For instance, you may be able to add something like 'is not empty' in addition to 'contains'.
I hope this helps.
Best regards,
Jeremy
Dear Ameer,
Thank you for your patience.
The development team analysed your reproducible case in the issue REVIT-172990 [Parameter filter with FilterStringContains returns false positive] that I logged for you and found the reason for this behaviour.
If the internal method ParameterValueProvider::getParameterValue() cannot get the parameter from the element itself, will also try to get it from the element's type:
if (m_elemOrSymbol == EOS_Symbol
|| err != ERR_SUCCESS || !oParameterValue)
{
ElementId typeId = pElement->getTypeId();
if (validElementId(typeId))
{
const Element *pTypeElement
= pElement->getDocument()->getElement(typeId);
if (pTypeElement != NULL)
{
oParameterValue = pTypeElement->getParameterValue(
m_parameter);
err = getErrFromParameterValue(oParameterValue);
if (err != ERR_SUCCESS)
{
return nullptr;
}
}
}
}
Therefore, yes, you cannot find the parameter in the walls.
However, you can find the parameters in their wall type!
That's why you can still get those walls.
This behaviour has been in effect for a long time, so we should not think about changing it.
However, if the documentation and knowledge base does not mention this behaviour, this information must be added.
We therefore closed REVIT-172990 [Parameter filter with FilterStringContains returns false positive] and raised a new issue REVIT-173253 [Parameter filter with FilterStringContains returns false positive] for the documentation team to document this behaviour. Please make a note of this number for future reference.
I hope this clarifies.
Best regards,
Jeremy
Hi @jeremy_tammik
Thanks!
I am going to accept your reply as an accepted answer but it is not as expected.
If you have time, check my following questions:
1-
Therefore, yes, you cannot find the parameter in the walls.
However, you can find the parameters in their wall type!
I think this behaviour is not acceptable logically even though it was in effect for a long time. at least it should return the wall type itself rather than returning all walls under that type.
2- can it be modified to have a boolean to search through the element's type or not? or like the element collection i.e. WhereElementIsElementType / WhereElementIsNotElementType
FilteredElementCollector collector = new FilteredElementCollector(doc); collector.WhereElementIsNotElementType()
I agree that this behaviour defeats part of the purpose of the parameter filter.
If I were you, I would choose the simple solution of filtering for parameters that are guaranteed not to be present on the type.
I always preferred the functionality as it is now. There are various solutions out there for finding elements that rely on not having to separately look through the parameters on the type or know that a parameter is on a type or an instance.
Imagine you want to find all instances that have a certain type parameter, you would first have to filter for all types, filter those for the parameter match, then filter again for all instances that are of one of those types. This is already a common approach for a lot of cases where parameter filters canāt be used.
I thought it just saved a lot of work really, I see no need for a change. If you want to know the parameter is on the instance then put the results through a further filter. You can supply a list of ids to a further element filter at any time. If you want to know parameter is on the type, filter first for types. In general, I donāt see much use of Logical AND/OR Filters sometimes I wonder if their existence is known of? People seem to have other methods but again use: LogicalAndFilter with
ParameterElementFilter & ElementIsElementTypeFilter(Inverted = True)
ElementParmeterFilter is a slow filter so first should use other quick filter before it.
How it is working is how it works in the UI when you set up visibility filters i.e. there is no distinction between type and instance parameters there. I imagine this is the internal system that this filter class leverages.
When I consider further there is a bit of a hole in functionality there.
Since you are forced to get a list of elements and then rule out those that have a type parameter match not an instance parameter match i.e. there are four cases:
Parameter with matching name and value is on: Type, Instance, Both, Neither.
We can only find with filter that it is on: Either or Neither
So how would we find Elements with only a matching parameter on the Instance is the question? After filtering with ElementParameterFilter we would have to manually check via Linq perhaps. We only care that it is or isn't on the instance so that could simplify things.
Exactly what I meant by saying, defeats part of the purpose.
Thank you for fleshing it out in more detail.
Linq is super slow compared to the built-in parameter filter, and I see no other option to achieve the in-between distinctions.
I noticed the same behavior for the Parameter properties of an Element. Getting a parameter on an (family)instance by GUID or Definition also returns the type-parameter.
please update the documentation for these properties.
Wow!
I assume that your note implies:
> Getting a parameter on an (family)instance by GUID or Definition also returns the type-parameter...
Thank you very much for the information!
Again, I would suggest that the safest way to handle this behaviour is to ensure that all parameters of interest are defined either on the instance or the type, and not on both.
I added your note to the blog post as well:
Thank you for the info!
Can't find what you're looking for? Ask the community or share your knowledge.