Expressions are the building blocks of PropertyWizard formulas. They are like phrases in a language.
It’s useful to understand the different kinds of expressions in PropertyWizard, so you can put them together in different ways to write better formulas.
There are four main kinds of expression in PropertyWizard:
Also called ‘literals’, these are where you type a value directly in the formula, such as typing
5 sq m
The value of the literal expression is the value you type.
These are the names of properties, such as
The value of the identifier expression is the value of the property.
These are the expressions that use the standard maths and logical operators like the plus sign:
<number expr> + <number expr>
You can see how this expression contains two <number expr> sub-expressions. It’s a type of Composite Expression, in contrast to the Simple expressions (literal and identifier expressions)
The sub-expressions have to return the right data type – in this case Number data. But they can be any kind of expression – literals, identifiers, operator expressions or functions – that produce that data type in the end. This is how you can build up arbitrarily complex formulas to do exactly what you need.
Function expressions are all of the form:
<function name>(<zero or more argument expressions separated by commas>)
They provide more complex functionality than operator expressions. Each function defines how many ‘arguments’ it takes, and what their data types should be. And as with operator expressions, each of the arguments can be any kind of expression as long as it produces the right data type.
All function expressions are Composite except pi(), which has no arguments.
How to use expressions
Every formula has to be an expression. If that’s a Simple expression, then that’s all there is. If it’s a Composite expression, then it will contain sub-expressions that may in turn be either Simple or Composite. There’s no practical limit to how complex your expression nesting can get.
When you make a new Revit parameter you choose the Type of Parameter, and that determines the type of data that the parameter can hold:
PropertyWizard uses these same data types:
True/False (equivalent to Yes/No)
Angle (measured in radians)
The only oddity is XYZ, which is a Revit API type. It is only valid as input to the internalToShared() and sharedToInternal() functions.
Formulas have data types
It follows that each formula produces a result of a particular data type. It’s important that the formula result is compatible with the Target Property:
Number or Integer
Number or Integer (see Note 1)
Any (see Note 2)
Angle (see Note 3)
Currency (see Note 3)
Note 1: When setting Integer parameters, Number values are rounded down. For more control, you will usually want to carry out the rounding within your formula.
Note 2: PropertyWizard will convert virtually all values to text when setting Text parameters. Dimension values (Length, Area, and Volume) will be converted using the current Revit project’s Units settings.
Note 3: Angle and Currency parameters can currently be set with any numeric value. Please do not rely on this: I will tighten it up in a future version of PropertyWizard.
Behind the scenes, the PropertyWizard data types are stored in .Net data types. You may see these data types in error messages. The details may vary in future versions.
PropertyWizard Data Type
Implementation Data Type
Double (see Note 4)
Note 4: Best practice would suggest storing Currency values in a Decimal form. Revit’s implementation uses Doubles to store currency values, so PropertyWizard follows suit. This may change in the future.
The <filter criteria> is where you choose which elements to affect, and the <target parameter> is the name of the formula’s target parameter. The <your formula> is where you put the formula that you want to apply to the selected elements.
For example, to affect only elements on Level 1, your filter criteria would be something like this:
This technique works because, when PropertyWizard evaluates the if() function for each element, it starts by evaluating the <filter criteria>. If that returns ‘true’, meaning that the element passes the filter, the if() function returns the value of <your formula>.
On the other hand, if the element doesn’t pass the filter, the if() function will return the value of the <target parameter>, and since that is equal to the actual <target parameter>, the formula has no effect.
This leaves the other elements uncontrolled
You will have noticed that, normally, if you change the value of a parameter that’s controlled by a formula, PropertyWizard immediately changes it back.
However, if you use this technique, the elements that don’t pass the filter aren’t controlled by the formula. So you are free to edit the value of the target parameter on these uncontrolled elements.
When PropertyWizard evaluates an if() function, it starts with the <condition>. For example in this formula:
if(Level.Name == "Level 0", "It's Level 0!", "It's some other Level!")
It will start by evaluating this expression:
Level.Name == "Level 0"
In PropertyWizard, the double-equals-sign ‘==’ means ‘is equal to’. So the value of the expression will be ‘true’ if the element’s Level’s Name is equal to “Level 0” and ‘false’ otherwise.
PropertyWizard uses the value of the <condition> to decide which value to return from the if() as a whole. If the <condition> evaluates to ‘true’, it returns the <result-if-true>, and if the <condition> is ‘false’ it returns the <result-if-false>.
Nested if() functions
You can nest if() functions to code more complex logic. For example, you can check whether the level name is “Level 0”, “Level 1” or some other Level like this:
if(Level.Name == "Level 0", "It's Level 0!", if(Level.Name == "Level 1", "It's Level 1!", "It's some other Level!"))
Here, the outer if() has the same <condition> as before, and the same <result-if-true>. But the <result-if-false> is a nested if() function:
if(Level.Name == "Level 1", "It's Level 1!", "It's some other Level!")
So when the outer if()’s <condition> returns ‘false’, PropertyWizard goes on to evaluate this inner if() and decide whether the level name is “Level 1” or not.
You can put a nested if into the <result-if-true> as well., and you can have multiple layers of nesting. With complex nesting, it can get tricky to put all the commas and parentheses in the right place: I tend to start small and evaluate each piece individually, and then gradually assemble the formula. It is easier to find errors if you make small changes and test as you go along.
Revit’s ‘Filters’ feature is great for highlighting elements based on their parameters, but you are restricted in which parameters you can use.
For Walls, for example, you cannot use any of these ‘Constraints’ parameters in a filter:
PropertyWizard lets you overcome this restriction – because you can set up a formula to copy the values of these ‘forbidden’ parameters into another parameter of your choice, and then you can set up a filter using that new, unrestricted parameter. PropertyWizard keeps the new parameter value updated, so your filter will ‘just work’.
For example, you can set up a diagnostic view to colour walls by their Base Constraint Level like this:
First, set up a new project or shared parameter to hold the name of the level:
Next, set up a formula to copy the Name of the Base Constraint level:
And finally, set up filters to highlight the walls based on your new parameter:
Here, I have highlighted the walls at Level 0 in green, and the ones at Level 1 in blue: