This is blog post number 1900, just fyi, cf. The Building Coder index and table of contents.
Revit 2022 has been released and the time has come to migrate to the new version.
Updates for RevitLookup, the Visual Studio Revit add-in wizards and The Building Coder samples are in the works and not done yet... one-man-band lagging... all Revit 2021 add-ins should work just fine in Revit 2022 as well, though.
Two important features are the parameter API enhancements and built-in PDF export functionality. Initial issues with these two have already been discussed:
ParameterType
with ForgeTypeId
David Becroft of Autodesk and Maxim Stepannikov of BIM Planet, aka Максим Степанников or architect.bim, helped address the Revit API discussion forum question on Revit 2022 ParameterType.Text to ForgeTypeId:
Question: Could somebody please help me out with this conversion from the deprecated ParameterType
to ForgeTypeId
for the Revit 2022 API?
The 'old' code has a line like this:
if( parameter.Definition.ParameterType
== ParameterType.Text ) ...
What would be the 2022 equivalent for it?
It seems that the left side may be:
if( parameter.Definition.GetDataType() == ????) ....
But, for some reason, I cannot find what I have to use on right side of the operation... there must be something I am overlooking.
Answer: To perform this check you need to create instance of ForgeTypeId class. Use one of the SpecTypeId's properties to get value to compare with. In your case (for text parameter) you need Number property:
>>> element.Parameter[BuiltInParameter.ALL_MODEL_MARK].Definition.GetSpecTypeId() == SpecTypeId.Number True
Also take a look at the conversation
on how to use ForgeTypeId
.
Response: Oh dear!
This is super confusing.
I've just checked and parameter definitions that store TEXT have a SpecTypeId
= SpecTypeId.Number
.
Now how do you distinguish between actual Numbers and Text?
It looks like the problem is this:
The Autodesk.Revit.DB.InternalDefinition
class has:
ParameterType
– this can be: Invalid | Text | Integer | NumberUnitType
– seemingly, for Text type parameters, this is UT_Number
Now with ParameterType
becoming obsolete, we have to use Parameter.GetSpecTypeId
that SEEMINGLY corresponds to the UnitType
member above, and for Text parameters like Comment
, it has a value of SpecTypeId.Number
!
The question is: How can I know if a Parameter is Text or not in Revit 2022 – without using Definition.ParameterType ?
Same would apply to YesNo
type parameters... SpecTypeId
cannot be used to determine if a ParameterDefinition
is for a YesNo
type parameter...
And even more: The ONLY place where I can see if a parameter is a YesNo parameter is in the Parameter.Definition.ParameterType !! If ParameterType is obsolete... how to determine if a parameter is YesNo or something else?
Answer: It is a well-known fact that unit type of text is number.
Actually, I don't know why :-)
But you definitely should use the Number
property.
Each Parameter object also has a StorageType
property.
In case of a Yes/No parameter, its value is Integer
.
In case of Text parameter, String
.
I hope this solves your problem.
Response: Well, sorry for my ignorance but seemingly there is still one 'minor' issue left for me to be answered:
var option = new ExternalDefinitionCreationOptions( "ExampleParamForge", SpecTypeId.XXX ???); var definition = definitionGroup.Definitions.Create( option );
Using SpecTypeId.Number creates a Parameter that has the "Type of Parameter" set to Number (obviously!, right?)
How do I create a simple TEXT Parameter definition using the Revit 2022 API?
There must be something here that I am missing.
Answer: To create a text parameter, please use SpecTypeId.String.Text
.
For context, the ForgeTypeId
properties directly in the SpecTypeId
class identify the measurable data types, like SpecTypeId.Length
or SpecTypeId.Mass
.
The non-measurable data types are organized into nested classes within SpecTypeId
, like SpecTypeId.String.Text
, SpecTypeId.Boolean.YesNo
, SpecTypeId.Int.Integer
, or SpecTypeId.Reference.Material
.
Regarding text parameters that report their type as "Number", here's the history:
Definition
had a UnitType
and a ParameterType
.
The UnitType
property was only meaningful for parameters with measurable ParameterType
values, and a parameter with ParameterType.Text
would report a meaningless UnitType.Number
value.UnitType
property and replaced it with the GetSpecTypeId
method.
But the behaviour remained the same – a parameter with ParameterType.Text
would have GetSpecTypeId
== SpecTypeId.Number
.ParameterType
property and the GetSpecTypeId
method, replacing them both with the GetDataType
method.
A parameter with ParameterType.Text
will report GetDataType()
== SpecTypeId.String.Text
.
Side note: The GetDataType
method can also return a category identifier, indicating a Family Type parameter of that category.Many thanks to Maxim and David for their clarification!
Josiah Offord very kindly shared his solution to implement a multi-target add-in for several releases of Revit
using the Microsoft Build Engine MSBuild in both
a comment
on multi-targeting Revit Versions using TargetFrameworks
and in a dedicated Revit API discussion forum thread
on multi-targeting 2021 and 2022 using MSBuild
:
For those interested, you can configure a .csproj
to multi-target both 2021 and 2022 on .NET Framework 4.8 using MSBuild.
I posted this on a comment in The Building Coder blog and figured it'd be useful here too.
The first task is to choose what .NET 4.8 add-in you want to actively program against.
There can only be one active add-in per .NET framework as far as I know.
In this example, I'm setting my default to Revit 2022 using the custom RevitVersion
property if it hasn't been configured yet.
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop" InitialTargets="Test"> ... <PropertyGroup> <TargetFrameworks>net461;net47;net472;net48</TargetFrameworks> <Configurations>Debug;Release</Configurations> <OutputPath>bin\$(Configuration)\</OutputPath> <UseWindowsForms>true</UseWindowsForms> <RevitVersion Condition=" '$(RevitVersion)' == '' ">2022</RevitVersion> ... </PropertyGroup>
Next, define configurations changes per each version.
<PropertyGroup Condition=" '$(TargetFramework)' == 'net461' "> <PlatformTarget>x64</PlatformTarget> <DefineConstants>DEBUG;REVIT2018</DefineConstants> <OutputPath>bin\$(Configuration)\2018\</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFramework)' == 'net47' "> <PlatformTarget>x64</PlatformTarget> <DefineConstants>$(DefineConstants);REVIT2019</DefineConstants> <OutputPath>bin\$(Configuration)\2019</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFramework)' == 'net472' "> <PlatformTarget>x64</PlatformTarget> <DefineConstants>$(DefineConstants);REVIT2020</DefineConstants> <OutputPath>bin\$(Configuration)\2020\</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFramework)' == 'net48' And '$(RevitVersion)' == '2021' "> <PlatformTarget>x64</PlatformTarget> <DefineConstants>$(DefineConstants);REVIT2021</DefineConstants> <OutputPath>bin\$(Configuration)\2021</OutputPath> </PropertyGroup> <PropertyGroup Condition=" '$(TargetFramework)' == 'net48' And '$(RevitVersion)' == '2022' "> <PlatformTarget>x64</PlatformTarget> <DefineConstants>$(DefineConstants);REVIT2022</DefineConstants> <OutputPath>bin\$(Configuration)\2022</OutputPath> </PropertyGroup>
Next, load the proper dll references for each version.
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' "> <Reference Include="AdWindows"> <HintPath>C:\Program Files\Autodesk\Revit 2018\AdWindows.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPI"> <HintPath>C:\Program Files\Autodesk\Revit 2018\RevitAPI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPIUI"> <HintPath>C:\Program Files\Autodesk\Revit 2018\RevitAPIUI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net47' "> <Reference Include="AdWindows"> <HintPath>C:\Program Files\Autodesk\Revit 2019\AdWindows.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPI"> <HintPath>C:\Program Files\Autodesk\Revit 2019\RevitAPI.dll</HintPath> <Private>False</Private> <EmbedInteropTypes>false</EmbedInteropTypes> </Reference> <Reference Include="RevitAPIUI"> <HintPath>C:\Program Files\Autodesk\Revit 2019\RevitAPIUI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net472' "> <Reference Include="AdWindows"> <HintPath>C:\Program Files\Autodesk\Revit 2020\AdWindows.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPI"> <HintPath>C:\Program Files\Autodesk\Revit 2020\RevitAPI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPIUI"> <HintPath>C:\Program Files\Autodesk\Revit 2020\RevitAPIUI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net48' And '$(RevitVersion)' == '2021' "> <Reference Include="AdWindows"> <HintPath>C:\Program Files\Autodesk\Revit 2021\AdWindows.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPI"> <HintPath>C:\Program Files\Autodesk\Revit 2021\RevitAPI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPIUI"> <HintPath>C:\Program Files\Autodesk\Revit 2021\RevitAPIUI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> </ItemGroup> <ItemGroup Condition=" '$(TargetFramework)' == 'net48' And '$(RevitVersion)' == '2022' "> <Reference Include="AdWindows"> <HintPath>C:\Program Files\Autodesk\Revit 2022\AdWindows.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPI"> <HintPath>C:\Program Files\Autodesk\Revit 2022\RevitAPI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> <Reference Include="RevitAPIUI"> <HintPath>C:\Program Files\Autodesk\Revit 2022\RevitAPIUI.dll</HintPath> <EmbedInteropTypes>false</EmbedInteropTypes> <Private>false</Private> </Reference> </ItemGroup>
At the end, you need to configure an additional build for whatever .NET 4.8 Revit add-in you didn't set as the default above. This is nice because it will catch build errors even though the active .NET 4.8 version is something else.
<Target Name="Test"> <Message Importance="high" Text="-- Building $(MSBuildProjectFile), TF = $(TargetFramework), Config = $(Configuration), Revit Version = $(RevitVersion) --" /> </Target> <Target Name="Build2021" BeforeTargets="DispatchToInnerBuilds"> <Message Importance="high" Text="*** running pre-dispatch builds ***" /> <MSBuild Projects="myProject.csproj" Properties="Configuration=$(Configuration);TargetFramework=net48;RevitVersion=2021"></MSBuild> </Target>
Side note: Using a multi-target solution means you need to keep references to all the old versions of Revit. Be sure to copy out the needed dlls before removing that Revit version from your machine.
Hope this helps.
Thank you very much, Josiah, for this important and timely advice!
The new built-in PDF export is a certainly a very useful feature in Revit 2022 and has gathered a lot of interest.
Unfortunately, it also caused some misunderstandings, and a first problem was discovered and described in the thread on Revit 2022 PDF export fails with paper format set as default with other parameters.
The title says it all, and the development team explain:
By design, if PaperFormat is default, then PaperPlacement should always be Center. However, there is no restriction ensuring this on the API side. We should either silently set PaperPlacement to Center during export, or throw an exception notifying the add-in about this.
Currently, in this case, nothing happens and no warning or error is raised.
Another thread question why 2022 PDF exporter can't use the "sheet number" parameter.
Apparently, you have to be sure that the Sheet Number parameter from the "Parameter Type" drop down menu is selected from the Sheet type fields.
Also, if the sheet has no revision the filename, the words 'Current revision' may be inserted into the filename instead.
The development team confirm this fallback behaviour; if the parameter you selected is empty, it will fill the parameter name (Sample Value) in the filename.
The sheet number in the parameter set is confusing due to the parameter type. The designed scenario is: the customer will use this parameter only in either sheet or view, not in both of them. If you select a mixed type of both view and sheet with this parameter, one parameter will fallback to its name due to its absence in the view type.
Taking a quick look beyond Revit and .NET development for the desktop, the article on 5 mistakes beginner web developers make – and how to fix them addresses topics that are of use in a non-web environment as well, and that I actually adhere to pretty strictly myself on all platforms – possibly excepting the last – I am still practicing that:
index