Renombrado de parámetros compartidos (Rename shared parameter)

Renombrado de parámetros compartidos (Rename shared parameter)

pedro_abril
Participant Participant
819 Views
3 Replies
Message 1 of 4

Renombrado de parámetros compartidos (Rename shared parameter)

pedro_abril
Participant
Participant

Tengo la necesidad de renombrar unos parámetros compartidos por cambios en la nomenclatura de los nombres.

El problema es que al hacer los nuevos parámetros se utilizo el mismo GUID de los anteriores y eso genera errores al intentar cargarlos directamente.

 

Estoy desarrollando un pequeño script en python que comparto más abajo para intentar realizar esta tarea. La idea es convertir el parámetro original en un parámetro de familia, renombrarlo y volver a convertirlo en parámetro de familia.

 

Todo el proceso se realiza sin problemas hasta el último paso, donde se vuelve a convertir a parámetro compartido. Este último paso arroja un error muy poco descriptivo (Parameter replacement failed) por lo que no se como arreglarlo: 

[ERROR] Error in Transaction Context: has rolled back.
Exception : Autodesk.Revit.Exceptions.InvalidOperationException: Parameter replacement failed.
   at Microsoft.Scripting.Interpreter.ThrowInstruction.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.HandleException(InterpretedFrame frame, Exception exception)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
   at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
   at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope)
   at Microsoft.Scripting.Hosting.ScriptSource.ExecuteAndWrap(ScriptScope scope, ObjectHandle& exception)

 El código:

"pruebas de cambio de nombre de parametros compartidos"

from rpw import revit, db, ui, DB, UI

# Acceso global al FamilyManager
fm = doc.FamilyManager

# Obtenemos un parámetro compartido del archivo actual
def obtener_parametro_compartido(grupo, nombre):
	try:
		spFile = revit.app.OpenSharedParameterFile()
		spGroup = spFile.Groups.get_Item(grupo)
		spParam = spGroup.Definitions.get_Item(nombre)
		return spParam
	except:
		print(f"Parámetro {nombre} no encontrado.")

# Renombramos el parámetro compartido indicado
def renombrar_parametro_compartido (param, nombre):
	grupo = param.Definition.ParameterGroup
	deInstancia = param.IsInstance
	spGrupo = "220_CTN_ContentSTR"
	# Convertir en nuevo parámetro no compartido
	new_param = fm.ReplaceParameter(param, nombre, grupo, deInstancia)
	# Borrar el parámetro compartido anterior
	fm.RemoveParameter(param)
	# Volver a convertir a parámetro compartido
	spParam = obtener_parametro_compartido(spGrupo, "SNR_STR_Waterproof")
	fm.ReplaceParameter(new_param, spParam, grupo, deInstancia)
	print(f"\nParámetro renombrado: {new_param.Definition.Name}")

with db.Transaction("Nombre"):
	for param in fm.GetParameters():
		if param.Definition.Name == "SNR_Waterproof":
			renombrar_parametro_compartido(param, "SNR_STR_Waterproof")

El error se produce en la línea 29, donde se vuelve a generar el parámetro compartido.
(He probado como macro en C# y arroja el mismo error)

 

Gracias de antemano a quien me pueda ayudar

0 Likes
Accepted solutions (1)
820 Views
3 Replies
Replies (3)
Message 2 of 4

jeremy_tammik
Alumni
Alumni
Accepted solution

Muy difícil. Puede ser que es imposible. Aquí una explicación:

  

Alright, let's tackle the question of renaming shared parameters in Revit. This is a common point of confusion for Revit API developers.

The Short Answer: You cannot directly rename a shared parameter definition once it's created and especially if it's been used in a project.

The Why (and the workarounds):

The core issue lies in how Revit manages shared parameters. They are stored in an external text file (.txt) and referenced by their GUID (Globally Unique Identifier). This GUID is the immutable identifier. Renaming the parameter within the shared parameter file does not change the GUID. Therefore, Revit still recognizes the parameter by its original GUID, effectively ignoring the name change.

If the parameter is already used in a Revit project (assigned to families, project parameters, schedules, etc.), changing the name in the shared parameter file will lead to inconsistencies and potential data loss. Revit relies on the GUID to maintain the link between the project and the shared parameter definition.

What you can do (Workarounds):

Since direct renaming is impossible, we must employ workarounds. Here are the most common and effective approaches:

  1. Creating a New Shared Parameter and Transferring Values:

    This is the cleanest and most recommended approach.

    • Create a new shared parameter with the desired name and properties (type, group, etc.).
    • Use the Revit API to iterate through elements that use the old parameter.
    • Read the value of the old parameter for each element.
    • Set the value of the new parameter to the retrieved value.
    • (Optional) Remove the old parameter from the elements.

    Code Example (C#):

    C#
     
    using Autodesk.Revit.DB;
    using Autodesk.Revit.UI;
    using System.Collections.Generic;
    using System.Linq;
    
    public void RenameSharedParameter(Document doc, string oldParameterName, string newParameterName)
    {
        // Get the shared parameter file
        DefinitionFile sharedParamsFile = doc.Application.OpenSharedParameterFile();
        if (sharedParamsFile == null)
        {
            TaskDialog.Show("Error", "No shared parameter file found.");
            return;
        }
    
        //Find old parameter definition
        Definition oldDefinition = FindSharedParameterDefinition(sharedParamsFile, oldParameterName);
        if (oldDefinition == null)
        {
            TaskDialog.Show("Error", $"Parameter '{oldParameterName}' not found.");
            return;
        }
    
                //Find shared parameter group
                DefinitionGroup group = oldDefinition.OwnerGroup;
    
        // Create new parameter definition
        ExternalDefinitionCreationOptions options = new ExternalDefinitionCreationOptions(newParameterName, oldDefinition.ParameterType);
                Definition newDefinition = group.Definitions.Create(options);
    
        // Find all elements using the old parameter
        FilteredElementCollector collector = new FilteredElementCollector(doc);
        collector.WhereElementIsNotElementType(); // Exclude element types
    
        List<Element> elementsWithParameter = new List<Element>();
        foreach (Element element in collector)
        {
            if (element.GetParameters(oldParameterName).Count > 0)
            {
                elementsWithParameter.Add(element);
            }
        }
        using (Transaction trans = new Transaction(doc, "Transfer Parameter Values"))
        {
            trans.Start();
            foreach (Element element in elementsWithParameter)
            {
                Parameter oldParam = element.LookupParameter(oldParameterName);
                Parameter newParam = element.LookupParameter(newParameterName);
                if (oldParam != null && newParam != null)
                {
                    newParam.Set(oldParam.AsValueString()); // Transfer the value - Adapt as needed for different parameter types
                }
            }
            trans.Commit();
        }
    }
    
        private Definition FindSharedParameterDefinition(DefinitionFile file, string parameterName)
        {
            foreach (DefinitionGroup group in file.Groups)
            {
                foreach (Definition definition in group.Definitions)
                {
                    if (definition.Name == parameterName)
                    {
                        return definition;
                    }
                }
            }
            return null;
        }
    

    Key improvements in this code:

    • Handles DefinitionFile opening and error checking.
    • Uses FindSharedParameterDefinition function to locate shared parameter definition in the file.
    • Uses ExternalDefinitionCreationOptions to create new shared parameters.
    • Uses FilteredElementCollector to find all elements that use the old parameter.
    • Uses Transactions for data integrity.
    • Includes handling for different parameter types by using AsValueString(). Consider more robust type handling for real-world scenarios.
  2. Using a Parameter Binding File (Less Recommended):

    This approach is less common and generally not advised for simple renaming. It involves manipulating the parameter binding file (which links shared parameters to categories). It's complex and prone to errors.

In Summary:

Renaming shared parameters directly is not possible due to Revit's internal handling of GUIDs. The recommended approach is to create a new shared parameter and transfer the values from the old parameter to the new one using the Revit API. This ensures data integrity and avoids potential issues. The provided code example offers a robust and practical implementation of this method. Remember to adapt the value transfer part to handle different parameter types correctly.

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 3 of 4

pedro_abril
Participant
Participant

 

Thank you very much for the answer.
As you say, it is very difficult to handle this situation when they are already in use in a project.
Thanks for the example, I found it very didactic and I will reuse it in my tool.

It is true that my code is designed for families and once I try to load them in a project I get errors. It is only valid in new projects.

Anyway I publish the correction to my code for families:

 

(Translated with DeepL.com (free version))

 

Muchas gracias por la respuesta.
Como dices, es muy difícil manejar esta situación cuando ya están en uso en un proyecto.
Gracias por el ejemplo, me ha resultado muy didáctico y lo reutilizaré en mi herramienta.

Es verdad que mi código está pensado para familias y que una vez intento cargarlos en algún proyecto me da errores. Sólo es válido en proyectos nuevos.

De todas maneras publico la corrección a mi código para familias:

"pruebas de cambio de nombre de parametros compartidos"

from rpw import revit, db, ui, DB, UI

# Acceso global al FamilyManager
fm = doc.FamilyManager

# Obtenemos un parámetro compartido del archivo actual
def obtener_parametro_compartido(grupo, nombre):
	try:
		spFile = revit.app.OpenSharedParameterFile()
		spGroup = spFile.Groups.get_Item(grupo)
		spParam = spGroup.Definitions.get_Item(nombre)
		return spParam
	except:
		print(f"Parámetro {nombre} no encontrado.")

# Renombramos el parámetro compartido indicado
def renombrar_parametro_compartido (param, nombre):
	grupo = param.Definition.ParameterGroup
	deInstancia = param.IsInstance
	spGrupo = "220_CTN_ContentSTR"
	# Convertir en nuevo parámetro no compartido
        # CORRECCION: generamos un parametro intermedio
        # con diferente nombre, así no interfiere con el siguiente paso
	new_param = fm.ReplaceParameter(param, nombre + "_AUX", grupo, deInstancia)
	# Borrar el parámetro compartido anterior
	fm.RemoveParameter(param)
	# Volver a convertir a parámetro compartido
	spParam = obtener_parametro_compartido(spGrupo, "SNR_STR_Waterproof")
	fm.ReplaceParameter(new_param, spParam, grupo, deInstancia)
	print(f"\nParámetro renombrado: {spParam.Definition.Name}")

with db.Transaction("Nombre"):
	for param in fm.GetParameters():
		if param.Definition.Name == "SNR_Waterproof":
			renombrar_parametro_compartido(param, "SNR_STR_Waterproof")

 

 

Message 4 of 4

jeremy_tammik
Alumni
Alumni

Thank you for your appreciation and sample code!

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes