We have repeatedly discussed all kinds of different aspects of Revit element parameters, but not put together a topic group for them yet.
Today I am happy to present a pretty comprehensive overview and explanation of the process of defining a shared parameter by none less than Scott Conover himself, Senior Revit Engineering Manager:
Question: What do I need to do to programmatically create a shared parameter?
I would like to set the SetAllowVaryBetweenGroups
flag on it.
Answer: You create the details needed to define a shared parameter from ExternalDefinition
.
Existing shared parameter file entries can be read to become an ExternalDefinition
in your code, or you can create a new entry in the current shared parameter file using the DefinitionGroup.Create
method.
The sample code listed in the Revit API help file RevitAPI.chm
or the online Revit API docs
under InstanceBinding class shows
this process best.
Here is part of that sample snippet:
public bool SetNewParameterToInstanceWall( UIApplication app, DefinitionFile myDefinitionFile ) { // Create a new group in the shared parameters file DefinitionGroups myGroups = myDefinitionFile.Groups; DefinitionGroup myGroup = myGroups.Create( "MyParameters" ); // Create an instance definition in definition group MyParameters ExternalDefinitionCreationOptions option = new ExternalDefinitionCreationOptions( "Instance_ProductDate", ParameterType.Text ); // Don't let the user modify the value, only the API option.UserModifiable = false; // Set tooltip option.Description = "Wall product date"; Definition myDefinition_ProductDate = myGroup.Definitions.Create( option ); . . .
The return from DefinitionGroup.Create
is an ExternalDefinition
, even though the type declared is the parent class.
Once you have an ExternalDefinition
, you add it to the document.
There are several ways:
- Use
InstanceBinding
as shown in that sample. - Use
FamilyManager.AddParameter
to add the parameter to a family. - Use
FamilyManager.ReplaceParameter
to replace a family parameter with the shared one. - Use
SharedParameterElement.Create
to create the element that represents the parameter without binding it to any categories.
There are also some RebarShape
related utilities which I would not recommend for general usage but might be OK for rebar-specific code.
Once the parameter is in the document, it has an InternalDefinition
.
The best ways to get it:
- If you have the
ParameterElement
from #4 you can useParameterElement.GetDefinition
. - If you have the GUID (which you should, since it is provided by the
ExternalDefinition
), you can useSharedParameterElement.Lookup
followed byParameterElement.GetDefinition
. - If you have an instance of an element whose category has this parameter bound, get the
Parameter
and useParameter.Definition
.
Once you have the InternalDefinition
, you can access the vary across groups option as well as other things.
You can also use an InternalDefintion
for adding and removing InstanceBindings
to categories.
Many thanks to Scott for this nice comprehensive summary and overview!
Addemdum
Joshua Lumley pointed out some possible enhancements in his two comments below:
To run the code more than twice I added:
bool dgMatchFound = false; foreach( DefinitionGroup dg in myGroups ) { if( dg.Name == myGroupName ) { dgMatchFound = true; myGroup = dg; } } if( dgMatchFound == false ) { myGroup = myGroups.Create( myGroupName ); }
and
bool dMatchFound = false; foreach( Definition d in myGroup.Definitions ) { if( d.Name == newParameterName ) { dMatchFound = true; myDefinition_ProductDate = d; } } if( !dMatchFound ) { myDefinition_ProductDate = myGroup.Definitions.Create( option ); }
I called it like this:
DefinitionFile defFile = GetOrCreateSharedParamsFile( ActiveUIDocument.Application.Application ); bool AddParameterResult = SetNewParameterToInstanceWall( ActiveUIDocument.Application, defFile ); TaskDialog.Show( "Did it work", AddParameterResult.ToString() );
Many thanks to Josh for the helpful usage hints!