Title: Issues with Adding Shared Parameters to Generic Model In-Place Families in Revit
Hello everyone,
I’m currently working on a Revit project where I need to add shared parameters to selected Generic Model In-Place Families. I’m using Python scripts with the Revit API, and the process involves selecting specific in-place families and adding custom shared parameters from a predefined shared parameters file.
The script works fine for adding the parameters, but I’ve encountered an unexpected issue:
Problem: The script is not only applying the parameters to the selected in-place families but also appears to be affecting future in-place families. I believe this is because the script modifies the document’s ParameterBindings
, which applies to all instances of that category (Generic Model). This means any new in-place family created after running the script inherits these shared parameters, which is not the intended behavior.
What I Need:
- I want the script to only add the parameters to the selected generic model in-place families, without affecting any new families created afterward or any other model-in-place family
If anyone has experience handling in-place families or dealing with shared parameters in a way that only affects specific instances, your guidance would be much appreciated!
Thank you in advance for your help!
Best regards,
Dhru
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from Autodesk.Revit.Exceptions import InvalidOperationException
from Autodesk.Revit.UI.Selection import ObjectType
import os, time
from pychilizer import database, units, select, geo
from pyrevit import forms, script, revit, DB
from dfl_matrix.load import main as load_main
from dfl_matrix.unload import main as unload_main
from dfl_matrix.folderpath import main as folderpath_main
# Initialize script output
output = script.get_output()
load_main()
output.print_md("**Script Initiated** : Add DFL_Shared Parameters")
# Define the mapping of parameter groups
parameter_groups = {
"Text": BuiltInParameterGroup.PG_TEXT,
"Identity Data": BuiltInParameterGroup.PG_IDENTITY_DATA,
"Electrical": BuiltInParameterGroup.PG_ELECTRICAL,
"Plumbing": BuiltInParameterGroup.PG_PLUMBING,
"Other": BuiltInParameterGroup.PG_GENERAL,
}
def add_shared_parameter_to_in_place_family(doc, element, parameter_name, newDef, parameter_group, prefill_value=None):
try:
# Check if the parameter already exists
param = element.LookupParameter(parameter_name)
if param:
output.print_md("Parameter '%s' already exists." % parameter_name)
return
# Create a category set and add the category of the element
category_set = doc.Application.Create.NewCategorySet()
category_set.Insert(element.Category)
# Create an instance binding for the parameter
instanceBinding = doc.Application.Create.NewInstanceBinding(category_set)
# Determine the parameter group
group = parameter_groups.get(parameter_group, BuiltInParameterGroup.PG_DATA)
# Add the parameter to the document under the specified group
bindingMap = doc.ParameterBindings
bindingMap.Insert(newDef, instanceBinding, group)
# Re-fetch the parameter after adding it
param = element.LookupParameter(parameter_name)
# Prefill the parameter with a value if provided and applicable
if param and prefill_value is not None:
if param.StorageType == StorageType.String:
param.Set(prefill_value)
elif param.StorageType == StorageType.Double:
param.Set(UnitUtils.ConvertToInternalUnits(float(prefill_value), DisplayUnitType.DUT_WATTS))
elif param.StorageType == StorageType.Integer:
param.Set(int(prefill_value))
else:
output.print_md("Unsupported storage type for prefill value for '%s'." % parameter_name)
output.print_md("Parameter '%s' successfully added." % parameter_name)
except Exception as e:
output.print_md("An error occurred while adding '%s': %s" % (parameter_name, str(e)))
def main():
doc = revit.doc
# Start timing the script
start_time = time.time()
# Use pychilizer's selection method to select Generic Model In-Place Families
selection = select.select_with_cat_filter(DB.BuiltInCategory.OST_GenericModel, "Select Generic Model In-Place Families")
# Filter the selection for only In-Place Families
in_place_families = [elem for elem in selection if hasattr(elem, 'Symbol') and elem.Symbol.Family.IsInPlace]
if not in_place_families:
forms.alert("No Generic Model In-Place Families selected.", exitscript=True)
return
# Function to define folder paths (assuming this function exists)
DIRECTORY, DFLFAMILYLIBRARY_FOLDER, DFL2020_FOLDER = folderpath_main()
# Dynamically construct the shared parameters file path
shared_params_file_path = os.path.join(
DIRECTORY,
"5. REVIT",
"DFL_Shared_Parameter_File",
"DFL_Family_Parameters.txt"
)
output.print_md("**Shared parameters file path** : %s" % shared_params_file_path)
# Load the shared parameters file once
app = doc.Application
app.SharedParametersFilename = shared_params_file_path
sharedParamsFile = app.OpenSharedParameterFile()
if not sharedParamsFile:
output.print_md("No shared parameter file found.")
return
# Specify the parameters to add and prefill values
parameters_to_add = [
{"name": "Equipment Code", "group": "Text", "prefill": None},
{"name": "Equipment ID", "group": "Text", "prefill": None},
{"name": "Spa Feature", "group": "Text", "prefill": None}
]
# Start a single transaction for all operations
t = Transaction(doc, "Add Shared Parameters to In-Place Families")
try:
t.Start()
# Add each parameter to each selected in-place family
for param_data in parameters_to_add:
# Find the parameter definition in the shared parameters file
newDef = None
for defGroup in sharedParamsFile.Groups:
for defDef in defGroup.Definitions:
if defDef.Name == param_data["name"]:
newDef = defDef
break
if newDef:
break
if not newDef:
output.print_md("Parameter definition for '%s' not found in shared parameter file." % param_data["name"])
continue
for element in in_place_families:
add_shared_parameter_to_in_place_family(doc, element, param_data["name"], newDef, param_data["group"], param_data["prefill"])
# Commit the transaction
if t.GetStatus() == TransactionStatus.Started:
t.Commit()
except InvalidOperationException as ioex:
output.print_md("Operation was cancelled or an error occurred: %s" % str(ioex))
if t.GetStatus() == TransactionStatus.Started:
t.RollBack()
except Exception as ex:
output.print_md("An unexpected error occurred: %s" % str(ex))
if t.GetStatus() == TransactionStatus.Started:
t.RollBack()
finally:
# Ensure this block runs even if the transaction fails
end_time = time.time()
execution_time = end_time - start_time
output.print_md("Execution Time: %.2f seconds" % execution_time)
# Run the main function in a try-finally block
try:
main()
finally:
# Ensure the unload function is always called after main execution
unload_main()