Reputation: 1
I'm working on an automation project in Visual Studio using C#, but I still have limited experience and lack a lot of knowledge. revit errorThe script manage to download the IFC file and reload it using transactions, but it doesn't modify anything, and Revit shows me the message in the attached image. I'm also including the part of the code where I perform the transactions because I believe that's where I'm making mistakes. I really appreciate any help. Regards.
This is the part of the script to make a transaction on the linked IFC:
[Transaction(TransactionMode.Manual)] public class FillGeoPar : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; Application app = uiapp.Application;
try
{
// Obtener el diccionario de documentos vinculados IFC
RevitLinkChecker linkChecker = new RevitLinkChecker();
var diccDocsVinc = linkChecker.ObtenerDiccVincReload(doc, "ifc");
// Mostrar TaskDialog con los vínculos cargados
string vinculosCargados = string.Join("\n", diccDocsVinc.Keys);
TaskDialog.Show("Vínculos Cargados", $"Los siguientes vínculos IFC están cargados:\n{vinculosCargados}");
// Seleccionar archivo Excel
string dfRuta = SeleccionarArchivoExcel();
if (string.IsNullOrEmpty(dfRuta))
{
message = "No se seleccionó ningún archivo Excel.";
return Result.Cancelled;
}
// Seleccionar hoja del Excel
string dfHoja = SeleccionarHojaExcel(dfRuta);
if (dfHoja == null)
{
message = "No se seleccionó ninguna hoja de Excel.";
return Result.Cancelled;
}
// Obtener DataFrame del Excel
var df = ObtenerDataFrameExcel(dfRuta, dfHoja);
if (df == null)
{
message = "No se pudo obtener la hoja del archivo Excel.";
return Result.Failed;
}
// Mostrar la primera columna en un diálogo
var primeraColumna = df.AsEnumerable().Select(row => row[0].ToString()).ToList();
TaskDialog.Show("Primera Columna", string.Join("\n", primeraColumna));
// Descargar todos los vínculos fuera de la transacción
var loadedExternalFilesRef = new List<RevitLinkType>();
var collector = new FilteredElementCollector(doc);
foreach (Element element in collector.OfClass(typeof(RevitLinkType)))
{
ExternalFileReference extFileRef = element.GetExternalFileReference();
if (extFileRef == null || extFileRef.GetLinkedFileStatus() != LinkedFileStatus.Loaded)
continue;
var revitLinkType = (RevitLinkType)element;
loadedExternalFilesRef.Add(revitLinkType);
revitLinkType.Unload(null);
}
// Reabrir los vínculos y modificar parámetros
foreach (var revitLinkType in loadedExternalFilesRef)
{
// Obtener la ruta del archivo vinculado
ExternalFileReference extFileRef = revitLinkType.GetExternalFileReference();
string rutaVinc = ModelPathUtils.ConvertModelPathToUserVisiblePath(extFileRef.GetAbsolutePath());
// Abrir el documento del vínculo
Document linkDoc = app.OpenDocumentFile(rutaVinc);
// Verificar y asignar los parámetros de los elementos vinculados que coinciden con las columnas del Excel
using (Transaction trans = new Transaction(linkDoc, "Modificar Parámetros Elementos Vinculados"))
{
trans.Start();
var nombresColumnasIFC = VerificarColumnasIFC(diccDocsVinc, df, linkDoc);
var colector = new FilteredElementCollector(linkDoc)
.WhereElementIsNotElementType()
.ToList();
foreach (var element in colector)
{
IList<Parameter> parametros = element.GetOrderedParameters();
Parameter nombreCodigoParam = parametros.FirstOrDefault(p => p.Definition != null && p.Definition.Name.Contains("NombreCódigo"));
if (nombreCodigoParam != null)
{
string nombreCodigo = nombreCodigoParam.AsString();
if (!string.IsNullOrEmpty(nombreCodigo) && primeraColumna.Contains(nombreCodigo))
{
DataRow filaExcel = df.AsEnumerable().FirstOrDefault(row => row[0].ToString() == nombreCodigo);
if (filaExcel != null)
{
foreach (Parameter param in parametros)
{
if (param.Definition != null)
{
string paramName = param.Definition.Name;
string columna = nombresColumnasIFC.FirstOrDefault(col => paramName.EndsWith(col, StringComparison.OrdinalIgnoreCase));
if (columna != null && df.Columns.Contains(columna))
{
string valorExcel = filaExcel[columna].ToString();
if (!string.IsNullOrEmpty(valorExcel))
{
if (param.StorageType == StorageType.String)
{
param.Set(valorExcel);
}
else if (param.StorageType == StorageType.Double && double.TryParse(valorExcel, out double valorDouble))
{
param.Set(valorDouble);
}
else if (param.StorageType == StorageType.Integer && int.TryParse(valorExcel, out int valorInt))
{
param.Set(valorInt);
}
else if (param.StorageType == StorageType.ElementId && int.TryParse(valorExcel, out int valorElementId))
{
param.Set(new ElementId(valorElementId));
}
}
}
}
}
}
}
}
}
trans.Commit();
}
// Cerrar el documento del vínculo
linkDoc.Close(false);
// Recargar el vínculo
revitLinkType.Load();
}
// Regenerar el documento principal
doc.Regenerate();
TaskDialog.Show("Éxito", "Parámetros modificados y guardados correctamente.");
return Result.Succeeded;
}
catch (Exception ex)
{
message = ex.Message;
return Result.Failed;
}
}
The script I'm trying to develop involves creating an add-in for Revit, which, with a linked IFC file, establishes a relationship between data from an Excel table and parameters of elements within this IFC file, attempting to modify these parameters with the data from the table.
Upvotes: 0
Views: 124
Reputation: 8339
Your code is long and hard to understand. The error message clearly indicates that you are attempting to modify the document outside a transaction. You have one transaction in there, but some modifications are happening outside of the transaction scope. I suggest you clean up your code and split it into smaller separate logical units to make it easier to understand the logic.
Upvotes: 0