Add Shared Parameter - Binding - Revit 2023

Error:
doc.ParameterBindings.Insert(parameter, binding, group_type)
optionally I have tried
doc.ParameterBindings.Insert(parameter, binding, spec_type)

Issue:
I think my issue is the deprecated use of Insert(Definition, Binding, BuiltInParameterGroup) and need to use Insert(Definition, Binding, ForgeTypeId). However I seem to be doing both wrong.

Ask:
Any assistance is appreciated. I am willing to research any references someone can provide. I have looked through several examples but seem to be missing something. Thank you to anyone willing to offer help!

Why & Thanks:
I know there are Nodes that do this, (Revit - Parameter.CreateProjectParameter, archilab - Add Shared Parameter to Project that I also can not use as python as I seem to have the same issue as , exct…). I am doing this to test my skills and learn. Thank you community for the following resources, The Building Coder: What's New in the Revit 2022 API,
https://forums.autodesk.com/t5/revit-api-forum/revit-2022-parametertype-text-to-forgetypeid/m-p/1h025741,
The Building Coder: PDF Export, ForgeTypeId and Multi-Target Add-In,
Help,
DynamoRevit/Parameter.cs at master · DynamoDS/DynamoRevit · GitHub). I also understand there is a Wall Type Parameter named Function. However I want to add my own in this experiment.

Full Code:

import clr
import tempfile

clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Get the Revit application and document
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

# Inputs
parameter_name = "WallFunction"  # Name of the parameter to create
group_name = "Wallz" # Name of the parameter group to create
spec_type = SpecTypeId.String.Text  # Data type of the parameter to create
group_type = "PG_DATA"  # Group type of the parameter to create (BuiltInParameterGroup Enumeration, i.e. PG_DATA)
instance = True # Instance or type parameter


# Start a new transaction
TransactionManager.Instance.EnsureInTransaction(doc)

try:
    # get current shared parameter file
    original_shared_parameter_file = doc.Application.SharedParametersFilename
    
    # Create a temporary shared parameter file
    temp_shared_parameter_file = tempfile.NamedTemporaryFile(suffix=".txt").name
    open(temp_shared_parameter_file, 'w').close()
    doc.Application.SharedParametersFilename = temp_shared_parameter_file

    # Apply the Walls category to the parameter
    category = Category.GetCategory(doc, BuiltInCategory.OST_Walls)
    binding = InstanceBinding(category)

    # Create the parameter and apply the binding
    group = doc.Application.OpenSharedParameterFile().Groups.Create(group_name)
    options = ExternalDefinitionCreationOptions(parameter_name, spec_type)
    options.ParameterGroup = group_type
    parameter = group.Definitions.Create(options)
    doc.ParameterBindings.Insert(parameter, binding, group_type)

    # Revert to the original shared parameter file
    #doc.Application.SharedParametersFilename = original_shared_parameter_file

    # Commit the transaction
    TransactionManager.Instance.TransactionTaskDone()
except Exception as e:
    # Rollback the transaction on error
    TransactionManager.Instance.TransactionTaskDone()
    TransactionManager.Instance.ForceCloseTransaction()
    raise e

OUT = binding, group, options, parameter

Yep. you need ForgeId’s for everything now.
I’d start with Jeremy’s site and go from theer. Not that difficult. Just different.
The Building Coder (typepad.com)

2 Likes

Not understanding how to go from BuiltInParameterGroup Enumeration to ForgeTypeId…
If this was not there what would one do to get it? I asume as it says this may not be there in 2024.

public static BuiltInParameterGroup GetBuiltInParameterGroup(
	ForgeTypeId groupTypeId
)

Also just tried unsuccessfully:
doc.ParameterBindings.Insert(parameter, binding, BuiltInParameterGroup.PG_DATA)

it all changed in 2023. 2022 was the last of not using Forge.
ParameterType dies with 2022.
If you look at the parameters with Snoop you can get some insight.
You’ll need to create a ForgeTypeId with the ForgeTypeId constructor and pass that to the method for the parameter.

Help | ForgeTypeId | Autodesk
…and note:

  • Category.GetBuiltInCategoryTypeId(BuiltInCategory)
  • Category.GetBuiltInCategory(ForgeTypeId)
2 Likes

I am still missing the macro understanding/ flow of what needs to take place.

my_forge_type_id2 = ForgeTypeId(BuiltInParameterGroup.PG_TEXT)

doc.ParameterBindings.Insert(definition, binding, my_forge_type_id2)

@aaronrumple Thank you so much for the help. I am still to inexperienced at this point to get this done. I will have to revisit it later as I have used my dedicated time and then some on this issue today.

Hi,
just for info, although it is possible to work with ForgeTypeId, BuiltInParameterGroup Enum is not deprecated in Revit 2022, 2023

example works with both Python engine in Revit 2023.1

add shared parameter

import clr
import System
import sys
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 

groupName = IN[0]
parameterName = IN[1]

spf = app.OpenSharedParameterFile()
if spf is not None:
	spfGroups = spf.Groups
	myExtdef = spfGroups.get_Item(groupName).Definitions.get_Item(parameterName)
	TransactionManager.Instance.EnsureInTransaction(doc)
	catSet =  CategorySet()
	catSet.Insert(Category.GetCategory(doc, BuiltInCategory.OST_Walls))
	binding = InstanceBinding(catSet)
	doc.ParameterBindings.Insert(myExtdef, binding, BuiltInParameterGroup.PG_DATA)
	TransactionManager.Instance.TransactionTaskDone()
	OUT =  myExtdef

if you want to works with ForgeTypeId

replace
doc.ParameterBindings.Insert(myExtdef, binding, BuiltInParameterGroup.PG_DATA)
with
doc.ParameterBindings.Insert(myExtdef, binding, GroupTypeId.Data)

4 Likes

@c.poupin Thank you so much for the time you spent posting! I have tried your code directly with the ForgeTypeId GroupTypeId.Data that is an example of just the binding of a shared parmater that exist. I need to study this and and work it into my code as my first pass did no work. I will repost tomorrow with my results. Thanks again @c.poupin !

1 Like

@c.poupin, thank you so much for your help! With your guidance, I was able to write working code and gain a better understanding of the topic. I will definitely put this knowledge to the test in future endeavors.

Here’s the code I ended up with, which is a combination of the community’s efforts. I’ve added comments to make it easier for future learners to understand. If anyone has suggestions for improvements, please feel free to comment.

For those who are new to this, I just want to note that I’ve used internally defined parameters, which can be changed to external parameters using the IN[0] syntax. This particular code only processes a single parameter and category, so loops would be necessary if multiple parameters need to be processed.

Once again, thank you for your time and for helping the community!

"""
Create a new shared parameter for Revit walls.

Inputs:
    parameter_name (str): Name of the parameter to create.
    group_name (str): Name of the parameter group to create.
    spec_type (str): Data type of the parameter to create (e.g. "Text", "Integer").
    group_type (str): Group type of the parameter to create (BuiltInParameterGroup Enumeration, i.e. PG_DATA).
    instance (bool): If True, create an instance parameter. If False, create a type parameter.

Returns:
    ExternalDefinition: The created shared parameter definition.
    
Process:
    The reason for creating a temporary file is to ensure that the parameter is created in the correct file with the desired configuration. By creating a temporary file, the script can control the exact path and name of the file, which is necessary for the next steps. The code imports the temporary file and adds the shared parameter to it, then retrieves it and applies it to the desired element type. Once the parameter has been created and bound, the temporary file can be removed, and the original shared parameter file can be reverted to its previous state. Overall, creating a temporary file ensures that the parameter is created as desired and then added to the correct shared parameter file.
"""
# Import required modules
import clr # Common Language Runtime module to interface with .NET libraries
import tempfile # Library for working with temporary files

# Add references to the required Revit modules
clr.AddReference('RevitAPI') # Revit API (Application Programming Interface) module
clr.AddReference('RevitAPIUI') # Revit API User Interface module
from Autodesk.Revit.DB import * # Import Revit's database objects
from Autodesk.Revit.UI import * # Import Revit's User Interface objects

# Add reference to the RevitServices module
clr.AddReference('RevitServices') # Add a reference to the RevitServices module to access its functionality
import RevitServices # Import the RevitServices module to access its classes and functions
from RevitServices.Persistence import DocumentManager # Import the DocumentManager class from the RevitServices.Persistence module
from RevitServices.Transactions import TransactionManager # Import the TransactionManager class from the RevitServices.Transactions module

# Get the current document and Revit application
doc = DocumentManager.Instance.CurrentDBDocument # Current Revit document
uiapp = DocumentManager.Instance.CurrentUIApplication # Current Revit application UI
app = uiapp.Application # Current Revit application
uidoc = uiapp.ActiveUIDocument # Active Revit UI document

# Inputs
parameter_name = "WallFunction"  # Name of the parameter to create
group_name = "Wallz" # Name of the parameter group to create
spec_type = SpecTypeId.String.Text  # Data type of the parameter to create
group_type = "PG_DATA"  # Group type of the parameter to create (BuiltInParameterGroup Enumeration, i.e. PG_DATA)
instance = True # Instance or type parameter


# Start a new transaction
TransactionManager.Instance.EnsureInTransaction(doc)

try:
    # get current shared parameter file
    original_shared_parameter_file = doc.Application.SharedParametersFilename
    
    # Create a temporary shared parameter file with a .txt suffix
    temp_shared_parameter_file = tempfile.NamedTemporaryFile(suffix=".txt").name
    open(temp_shared_parameter_file, 'w').close() # Create an empty file with the given name in the previsously defined temp_shared_parameter_file
    doc.Application.SharedParametersFilename = temp_shared_parameter_file # Set current document's shared parameter filename to newly created temp file

    # Apply the Walls category to the parameter
    category = Category.GetCategory(doc, BuiltInCategory.OST_Walls) # Retrieve the Walls category enum to specify the type of element to which the parameter should be bound.
    binding = InstanceBinding(category) # Instance binding associates the parameter with specific instances of the chosen element category. 

    # Create the parameter and apply the binding
    group = doc.Application.OpenSharedParameterFile().Groups.Create(group_name) # Create the parameter group with the specified name
    options = ExternalDefinitionCreationOptions(parameter_name, spec_type) # Create options for the external definition with the specified parameter name and spec type
    options.ParameterGroup = group_type # Set the parameter group type for the external definition
    parameter = group.Definitions.Create(options)# Create the external definition (parameter) within the specified group using the given options
        
    # Open the shared parameter file
    spf = app.OpenSharedParameterFile()
    # Get the groups from the shared parameter file
    spfGroups = spf.Groups
    # Get the specific shared parameter definition
    myExtdef = spfGroups.get_Item(group_name).Definitions.get_Item(parameter_name)
    
    # Create a CategorySet containing the walls category
    catSet = CategorySet()
    catSet.Insert(Category.GetCategory(doc, BuiltInCategory.OST_Walls))
    # Create an instance binding using the CategorySet
    binding = InstanceBinding(catSet)
    # Add the shared parameter definition to the walls category
    doc.ParameterBindings.Insert(myExtdef, binding, GroupTypeId.Data)

    # Revert to the original shared parameter file
    doc.Application.SharedParametersFilename = original_shared_parameter_file

    # Commit the transaction
    TransactionManager.Instance.TransactionTaskDone()
except Exception as e:
    # Revert to the original shared parameter file
    doc.Application.SharedParametersFilename = original_shared_parameter_file
    # Rollback the transaction on error
    TransactionManager.Instance.TransactionTaskDone()
    TransactionManager.Instance.ForceCloseTransaction()
    raise e

OUT = myExtdef
1 Like