Capítulo 13: Tu primer script EPLAN
Parte II: Introducción a EPLAN API - Sección 3: Primeros pasos con EPLAN - Nivel: Intermedio
🎯 Objetivos de aprendizaje
Sección titulada «🎯 Objetivos de aprendizaje»Al finalizar este capítulo serás capaz de:
- Entender el atributo [Start] y su importancia
- Abrir proyectos EPLAN programáticamente
- Leer propiedades de proyectos (nombre, descripción, configuración)
- Usar SelectionSet para obtener proyecto actual
- Mostrar mensajes con BaseException
- Validar existencia de proyectos antes de procesarlos
- Crear tu primer script funcional completo que resuelve un problema real
- Manejar errores específicos de EPLAN API
📋 Requisitos previos
Sección titulada «📋 Requisitos previos»Antes de comenzar este capítulo debes:
- ✅ Haber completado el Capítulo 12
- ✅ Entender la arquitectura de EPLAN API
- ✅ Conocer namespaces principales
- ✅ Tener EPLAN Electric P8 instalado
- ✅ Tener al menos un proyecto EPLAN de prueba
🏆 Proyecto del capítulo
Sección titulada «🏆 Proyecto del capítulo»Validador Inteligente de Proyectos EPLAN
Al final de este capítulo habrás construido un script completo que:
- Valida que un proyecto esté abierto
- Lee todas las propiedades importantes del proyecto
- Verifica la configuración básica
- Cuenta páginas, funciones y dispositivos
- Detecta posibles problemas
- Genera un reporte profesional de validación
- Maneja todos los errores posibles
Tiempo estimado: 70-80 minutos
📚 Contenido
Sección titulada «📚 Contenido»1. El atributo [Start]: El punto de entrada
Sección titulada «1. El atributo [Start]: El punto de entrada»1.1 ¿Qué es [Start]?
Sección titulada «1.1 ¿Qué es [Start]?»El atributo [Start] marca el punto de entrada de tu script. Es donde EPLAN comienza a ejecutar tu código.
Analogía: Como la función main() en C/C++ o public static void Main() en C# de consola.
using Eplan.EplApi.ApplicationFramework;
public class MiPrimerScript{ [Start] public void Ejecutar() { // Tu código comienza aquí }}Reglas importantes:
- ✅ Debe ser un método
public - ✅ Puede llamarse como quieras (
Ejecutar,Run,Main, etc.) - ✅ Solo puede haber un método [Start] por archivo
- ✅ El método puede tener parámetros opcionales
- ✅ No tiene que devolver nada (puede ser
void)
1.2 Sintaxis completa
Sección titulada «1.2 Sintaxis completa»[Start]public void NombreDelMetodo(){ // Código del script}Variantes válidas:
// 1. Sin parámetros (más común)[Start]public void Ejecutar(){}
// 2. Con parámetros opcionales[Start]public void Ejecutar(string parametro = ""){}
// 3. Nombre en inglés[Start]public void Execute(){}
// 4. Nombre descriptivo[Start]public void ValidarProyecto(){}1.3 ¿Qué pasa si no hay [Start]?
Sección titulada «1.3 ¿Qué pasa si no hay [Start]?»// ❌ ERROR - EPLAN no sabe dónde empezarpublic class MiScript{ public void Metodo1() { } public void Metodo2() { } // ¿Cuál ejecutar?}
// ✓ CORRECTOpublic class MiScript{ [Start] // ← EPLAN ejecuta esto public void Ejecutar() { Metodo1(); Metodo2(); }
public void Metodo1() { } public void Metodo2() { }}2. Estructura básica de un script EPLAN
Sección titulada «2. Estructura básica de un script EPLAN»2.1 Template mínimo
Sección titulada «2.1 Template mínimo»//// Descripción: Descripción breve// Autor: Tu nombre// Fecha: 2025//
using System;using Eplan.EplApi.Base;using Eplan.EplApi.ApplicationFramework;
public class MiScript{ [Start] public void Ejecutar() { try { // Tu código aquí
new BaseException("Script ejecutado correctamente", MessageLevel.Message).FixMessage(); } catch (Exception ex) { new BaseException("Error: " + ex.Message, MessageLevel.Error).FixMessage(); } }}2.2 Template completo recomendado
Sección titulada «2.2 Template completo recomendado»//// Descripción: [Descripción detallada]// Autor: [Tu nombre]// Fecha: [Fecha]// Versión: 1.0//// Uso:// 1. Abrir proyecto en EPLAN// 2. Ejecutar: Utilidades > Scripts > MiScript// 3. [Instrucciones específicas]//// Requisitos:// - EPLAN Electric P8 2023+// - Proyecto abierto//
using System;using System.Collections.Generic;using Eplan.EplApi.Base;using Eplan.EplApi.ApplicationFramework;using Eplan.EplApi.DataModel;
public class MiScript{ [Start] public void Ejecutar() { try { // ==================================== // 1. VALIDACIONES INICIALES // ==================================== if (!ValidarPrecondiciones()) { return; // Salir si no se cumplen requisitos }
// ==================================== // 2. LÓGICA PRINCIPAL // ==================================== ProcesarProyecto();
// ==================================== // 3. MENSAJE DE ÉXITO // ==================================== new BaseException("Proceso completado correctamente", MessageLevel.Message).FixMessage(); } catch (Exception ex) { // ==================================== // 4. MANEJO DE ERRORES // ==================================== string mensajeError = string.Format( "Error en el script:\n\n{0}\n\n{1}", ex.Message, ex.StackTrace);
new BaseException(mensajeError, MessageLevel.Error).FixMessage(); } }
private bool ValidarPrecondiciones() { // Validaciones aquí return true; }
private void ProcesarProyecto() { // Lógica principal aquí }}3. Obtener el proyecto actual
Sección titulada «3. Obtener el proyecto actual»3.1 Usando SelectionSet (recomendado)
Sección titulada «3.1 Usando SelectionSet (recomendado)»using Eplan.EplApi.ApplicationFramework;using Eplan.EplApi.DataModel;
[Start]public void Ejecutar(){ // Crear SelectionSet SelectionSet seleccion = new SelectionSet(); seleccion.LockSelectionByDefault = false;
// Obtener proyectos seleccionados Project[] proyectos = seleccion.GetSelectedProjects();
// Validar que hay al menos un proyecto if (proyectos.Length == 0) { new BaseException("No hay proyecto abierto", MessageLevel.Warning).FixMessage(); return; }
// Trabajar con el primer proyecto Project proyecto = proyectos[0];
string nombre = proyecto.ProjectName; new BaseException("Proyecto actual: " + nombre, MessageLevel.Message).FixMessage();}Explicación:
SelectionSet: Clase que maneja la selección actual en EPLANLockSelectionByDefault = false: No bloquear la selecciónGetSelectedProjects(): Obtiene array de proyectos seleccionados- Si hay múltiples proyectos abiertos, devuelve todos
3.2 Validación robusta
Sección titulada «3.2 Validación robusta»private Project ObtenerProyectoActual(){ try { SelectionSet seleccion = new SelectionSet(); seleccion.LockSelectionByDefault = false;
Project[] proyectos = seleccion.GetSelectedProjects();
if (proyectos == null || proyectos.Length == 0) { new BaseException( "No hay proyecto abierto.\n\n" + "Por favor, abre un proyecto en EPLAN antes de ejecutar este script.", MessageLevel.Warning).FixMessage(); return null; }
return proyectos[0]; } catch (Exception ex) { new BaseException( "Error al obtener proyecto actual:\n" + ex.Message, MessageLevel.Error).FixMessage(); return null; }}
// Uso[Start]public void Ejecutar(){ Project proyecto = ObtenerProyectoActual();
if (proyecto == null) return; // Salir si no hay proyecto
// Continuar con el procesamiento...}4. Leer propiedades del proyecto
Sección titulada «4. Leer propiedades del proyecto»4.1 Propiedades básicas
Sección titulada «4.1 Propiedades básicas»Project proyecto = ObtenerProyectoActual();
// Nombre del proyectostring nombre = proyecto.ProjectName;
// Descripciónstring descripcion = proyecto.ProjectDescription;
// Ruta completastring ruta = proyecto.ProjectFullName;
// Validez del objetobool esValido = proyecto.IsValid;
// Identificador únicoint objectId = proyecto.ObjectId;4.2 Propiedades con validación
Sección titulada «4.2 Propiedades con validación»// Descripción puede ser nullstring descripcion = proyecto.ProjectDescription;if (string.IsNullOrEmpty(descripcion)){ descripcion = "(Sin descripción)";}
// ProjectFullName incluye carpeta y extensiónstring rutaCompleta = proyecto.ProjectFullName;string carpeta = System.IO.Path.GetDirectoryName(rutaCompleta);string archivo = System.IO.Path.GetFileName(rutaCompleta);4.3 Propiedades mediante Properties
Sección titulada «4.3 Propiedades mediante Properties»EPLAN expone muchas propiedades adicionales a través del sistema Properties:
using Eplan.EplApi.DataModel;
Project proyecto = ObtenerProyectoActual();
// Acceder a PropertiesAnyPropertyId propId = new AnyPropertyId( Properties.Project.PROJ_COMPANYNAME);
string empresa = proyecto.Properties[propId].ToString();
// Otras propiedades comunesstring ciudad = proyecto.Properties[ new AnyPropertyId(Properties.Project.PROJ_COMPANY_TOWN)].ToString();
string pais = proyecto.Properties[ new AnyPropertyId(Properties.Project.PROJ_COMPANY_COUNTRY)].ToString();Propiedades importantes:
| Propiedad | Descripción | Ejemplo |
|---|---|---|
PROJ_COMPANYNAME | Nombre de empresa | ”ACME Corp” |
PROJ_COMPANY_TOWN | Ciudad | ”Madrid” |
PROJ_CUSTOMER | Cliente | ”Cliente XYZ” |
PROJ_PROJECTNUMBER | Número de proyecto | ”2025-001” |
PROJ_ORDERNUMBER | Número de pedido | ”ORD-12345” |
PROJ_DRAWINGDATE | Fecha de planos | ”2025-01-15” |
4.4 Leer propiedades con seguridad
Sección titulada «4.4 Leer propiedades con seguridad»private string ObtenerPropiedad(Project proyecto, int propertyId, string valorPorDefecto = "N/A"){ try { AnyPropertyId propId = new AnyPropertyId(propertyId);
if (!proyecto.Properties.ExistsProperty(propId)) { return valorPorDefecto; }
string valor = proyecto.Properties[propId].ToString();
if (string.IsNullOrWhiteSpace(valor)) { return valorPorDefecto; }
return valor; } catch { return valorPorDefecto; }}
// Usostring empresa = ObtenerPropiedad(proyecto, Properties.Project.PROJ_COMPANYNAME, "(Sin empresa)");5. Contar elementos del proyecto
Sección titulada «5. Contar elementos del proyecto»5.1 Contar páginas
Sección titulada «5.1 Contar páginas»Project proyecto = ObtenerProyectoActual();
Page[] paginas = proyecto.Pages;int totalPaginas = paginas.Length;
new BaseException( string.Format("El proyecto tiene {0} páginas", totalPaginas), MessageLevel.Message).FixMessage();5.2 Contar funciones y dispositivos
Sección titulada «5.2 Contar funciones y dispositivos»Project proyecto = ObtenerProyectoActual();
int totalFunciones = 0;int totalDispositivos = 0;
foreach (Page pagina in proyecto.Pages){ totalFunciones += pagina.Functions.Length; totalDispositivos += pagina.Devices.Length;}
string mensaje = string.Format( "ESTADÍSTICAS DEL PROYECTO:\n\n" + "Páginas: {0}\n" + "Funciones: {1}\n" + "Dispositivos: {2}", proyecto.Pages.Length, totalFunciones, totalDispositivos);
new BaseException(mensaje, MessageLevel.Message).FixMessage();5.3 Análisis completo
Sección titulada «5.3 Análisis completo»private void AnalizarProyecto(Project proyecto){ int totalPaginas = 0; int totalFunciones = 0; int totalDispositivos = 0; int totalConexiones = 0;
Dictionary<string, int> funcionesPorTipo = new Dictionary<string, int>();
foreach (Page pagina in proyecto.Pages) { totalPaginas++;
Function[] funciones = pagina.Functions; totalFunciones += funciones.Length;
totalDispositivos += pagina.Devices.Length;
// Analizar funciones foreach (Function funcion in funciones) { // Contar conexiones totalConexiones += funcion.Connections.Length;
// Contar por tipo string tipo = funcion.FunctionDefinition; if (string.IsNullOrEmpty(tipo)) tipo = "Sin tipo";
if (!funcionesPorTipo.ContainsKey(tipo)) { funcionesPorTipo[tipo] = 0; } funcionesPorTipo[tipo]++; } }
// Generar reporte string reporte = "ANÁLISIS COMPLETO DEL PROYECTO\n"; reporte += "========================================\n\n"; reporte += string.Format("Páginas: {0}\n", totalPaginas); reporte += string.Format("Funciones: {0}\n", totalFunciones); reporte += string.Format("Dispositivos: {0}\n", totalDispositivos); reporte += string.Format("Conexiones: {0}\n\n", totalConexiones);
reporte += "FUNCIONES POR TIPO:\n"; reporte += "----------------------------------------\n"; foreach (var kvp in funcionesPorTipo) { reporte += string.Format(" {0}: {1}\n", kvp.Key, kvp.Value); }
new BaseException(reporte, MessageLevel.Message).FixMessage();}6. Mostrar mensajes al usuario
Sección titulada «6. Mostrar mensajes al usuario»6.1 BaseException: Tres niveles
Sección titulada «6.1 BaseException: Tres niveles»using Eplan.EplApi.Base;
// 1. MESSAGE (Información)BaseException info = new BaseException( "Proceso completado correctamente", MessageLevel.Message);info.FixMessage();
// 2. WARNING (Advertencia)BaseException warning = new BaseException( "Atención: Algunas páginas no tienen numeración", MessageLevel.Warning);warning.FixMessage();
// 3. ERROR (Error)BaseException error = new BaseException( "Error: No se pudo abrir el archivo", MessageLevel.Error);error.FixMessage();Diferencias visuales en EPLAN:
Message: Ícono de información (azul)Warning: Ícono de advertencia (amarillo)Error: Ícono de error (rojo)
6.2 Mensajes formateados
Sección titulada «6.2 Mensajes formateados»// Mensaje multilíneastring mensaje = "REPORTE DE VALIDACIÓN\n";mensaje += "========================================\n";mensaje += string.Format("Proyecto: {0}\n", proyecto.ProjectName);mensaje += string.Format("Páginas: {0}\n", proyecto.Pages.Length);mensaje += "========================================\n";
new BaseException(mensaje, MessageLevel.Message).FixMessage();
// Mensaje con formatostring mensajeFormateado = string.Format( "El proyecto '{0}' tiene:\n\n" + " • {1} páginas\n" + " • {2} funciones\n" + " • {3} dispositivos", proyecto.ProjectName, totalPaginas, totalFunciones, totalDispositivos);
new BaseException(mensajeFormateado, MessageLevel.Message).FixMessage();6.3 Preguntar al usuario (MessageBox alternativo)
Sección titulada «6.3 Preguntar al usuario (MessageBox alternativo)»// BaseException solo muestra, no pregunta// Para diálogos interactivos, usa System.Windows.Forms
using System.Windows.Forms;
DialogResult resultado = MessageBox.Show( "¿Desea continuar con el proceso?", "Confirmar", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (resultado == DialogResult.Yes){ // Usuario confirmó ProcesarProyecto();}else{ // Usuario canceló new BaseException("Proceso cancelado por el usuario", MessageLevel.Warning).FixMessage();}7. Manejo de errores específicos de EPLAN
Sección titulada «7. Manejo de errores específicos de EPLAN»7.1 Errores comunes
Sección titulada «7.1 Errores comunes»try{ SelectionSet sel = new SelectionSet(); Project[] proyectos = sel.GetSelectedProjects();
if (proyectos.Length == 0) { throw new InvalidOperationException("No hay proyecto abierto"); }
Project proyecto = proyectos[0];
// Trabajar con proyecto...}catch (InvalidOperationException ex){ // Error conocido - mensaje amigable new BaseException( "No se puede continuar:\n\n" + ex.Message, MessageLevel.Warning).FixMessage();}catch (System.Runtime.InteropServices.COMException ex){ // Error de COM (EPLAN API usa COM internamente) new BaseException( "Error de comunicación con EPLAN:\n\n" + "Intente cerrar y reabrir EPLAN.\n\n" + "Detalles técnicos: " + ex.Message, MessageLevel.Error).FixMessage();}catch (Exception ex){ // Error genérico new BaseException( "Error inesperado:\n\n" + ex.Message + "\n\n" + ex.StackTrace, MessageLevel.Error).FixMessage();}7.2 Validaciones preventivas
Sección titulada «7.2 Validaciones preventivas»private bool ValidarProyecto(Project proyecto){ // 1. Verificar que el objeto sea válido if (proyecto == null) { new BaseException("El proyecto es null", MessageLevel.Error).FixMessage(); return false; }
if (!proyecto.IsValid) { new BaseException("El proyecto no es válido", MessageLevel.Error).FixMessage(); return false; }
// 2. Verificar que tenga páginas if (proyecto.Pages == null || proyecto.Pages.Length == 0) { new BaseException( "El proyecto no tiene páginas.\n\n" + "No se puede continuar el procesamiento.", MessageLevel.Warning).FixMessage(); return false; }
// 3. Verificar que no esté vacío int totalFunciones = 0; foreach (Page pagina in proyecto.Pages) { totalFunciones += pagina.Functions.Length; }
if (totalFunciones == 0) { DialogResult resultado = MessageBox.Show( "El proyecto no tiene funciones (componentes).\n\n" + "¿Desea continuar de todos modos?", "Proyecto vacío", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
return resultado == DialogResult.Yes; }
return true;}💻 Manos a la obra: Proyecto completo
Sección titulada «💻 Manos a la obra: Proyecto completo»Validador Inteligente de Proyectos
Sección titulada «Validador Inteligente de Proyectos»//// Proyecto: Validador Inteligente de Proyectos EPLAN// Capítulo: 13// Descripción: Script completo que valida un proyecto EPLAN y genera// un reporte detallado con información, estadísticas y// detección de posibles problemas// Autor: C.D. López// Fecha: Enero 2025//// Uso:// 1. Abrir un proyecto en EPLAN// 2. Ejecutar: Utilidades > Scripts > ValidadorProyecto// 3. Se mostrará un reporte completo de validación//
using System;using System.Collections.Generic;using System.Linq;using Eplan.EplApi.Base;using Eplan.EplApi.ApplicationFramework;using Eplan.EplApi.DataModel;
public class ValidadorProyecto{ [Start] public void Ejecutar() { try { // ==================================== // 1. OBTENER PROYECTO ACTUAL // ==================================== Project proyecto = ObtenerProyectoActual();
if (proyecto == null) return;
// ==================================== // 2. VALIDAR PRECONDICIONES // ==================================== if (!ValidarProyecto(proyecto)) return;
// ==================================== // 3. RECOPILAR INFORMACIÓN // ==================================== string reporte = GenerarReporteCompleto(proyecto);
// ==================================== // 4. MOSTRAR REPORTE // ==================================== new BaseException(reporte, MessageLevel.Message).FixMessage(); } catch (Exception ex) { string mensajeError = string.Format( "ERROR EN VALIDADOR DE PROYECTO\n" + "========================================\n\n" + "Mensaje: {0}\n\n" + "Tipo: {1}\n\n" + "Stack Trace:\n{2}", ex.Message, ex.GetType().Name, ex.StackTrace);
new BaseException(mensajeError, MessageLevel.Error).FixMessage(); } }
// ==================================== // OBTENER PROYECTO ACTUAL // ==================================== private Project ObtenerProyectoActual() { try { SelectionSet seleccion = new SelectionSet(); seleccion.LockSelectionByDefault = false;
Project[] proyectos = seleccion.GetSelectedProjects();
if (proyectos == null || proyectos.Length == 0) { new BaseException( "NO HAY PROYECTO ABIERTO\n\n" + "Por favor, abre un proyecto en EPLAN antes de ejecutar este script.", MessageLevel.Warning).FixMessage(); return null; }
return proyectos[0]; } catch (Exception ex) { new BaseException( "Error al obtener proyecto actual:\n\n" + ex.Message, MessageLevel.Error).FixMessage(); return null; } }
// ==================================== // VALIDAR PROYECTO // ==================================== private bool ValidarProyecto(Project proyecto) { // Verificar validez del objeto if (!proyecto.IsValid) { new BaseException( "El proyecto no es válido.\n\n" + "Es posible que el proyecto esté corrupto o no se haya cargado correctamente.", MessageLevel.Error).FixMessage(); return false; }
// Verificar que tenga páginas if (proyecto.Pages == null || proyecto.Pages.Length == 0) { new BaseException( "El proyecto no tiene páginas.\n\n" + "No hay contenido para validar.", MessageLevel.Warning).FixMessage(); return false; }
return true; }
// ==================================== // GENERAR REPORTE COMPLETO // ==================================== private string GenerarReporteCompleto(Project proyecto) { string reporte = "VALIDADOR INTELIGENTE DE PROYECTOS EPLAN\n"; reporte += "========================================\n\n";
// Sección 1: Información básica reporte += GenerarSeccionInformacionBasica(proyecto);
// Sección 2: Propiedades del proyecto reporte += GenerarSeccionPropiedades(proyecto);
// Sección 3: Estadísticas reporte += GenerarSeccionEstadisticas(proyecto);
// Sección 4: Análisis de páginas reporte += GenerarSeccionPaginas(proyecto);
// Sección 5: Problemas detectados reporte += GenerarSeccionProblemas(proyecto);
// Sección 6: Conclusión reporte += GenerarSeccionConclu sion(proyecto);
return reporte; }
// ==================================== // SECCIÓN: INFORMACIÓN BÁSICA // ==================================== private string GenerarSeccionInformacionBasica(Project proyecto) { string seccion = "INFORMACIÓN BÁSICA:\n"; seccion += "----------------------------------------\n";
seccion += string.Format(" Nombre: {0}\n", proyecto.ProjectName);
string descripcion = proyecto.ProjectDescription; if (string.IsNullOrEmpty(descripcion)) descripcion = "(Sin descripción)"; seccion += string.Format(" Descripción: {0}\n", descripcion);
seccion += string.Format(" Ruta: {0}\n", proyecto.ProjectFullName); seccion += string.Format(" Es válido: {0}\n", proyecto.IsValid ? "Sí" : "No"); seccion += string.Format(" ObjectId: {0}\n\n", proyecto.ObjectId);
return seccion; }
// ==================================== // SECCIÓN: PROPIEDADES // ==================================== private string GenerarSeccionPropiedades(Project proyecto) { string seccion = "PROPIEDADES DEL PROYECTO:\n"; seccion += "----------------------------------------\n";
string empresa = ObtenerPropiedad(proyecto, Properties.Project.PROJ_COMPANYNAME); seccion += string.Format(" Empresa: {0}\n", empresa);
string ciudad = ObtenerPropiedad(proyecto, Properties.Project.PROJ_COMPANY_TOWN); seccion += string.Format(" Ciudad: {0}\n", ciudad);
string cliente = ObtenerPropiedad(proyecto, Properties.Project.PROJ_CUSTOMER); seccion += string.Format(" Cliente: {0}\n", cliente);
string numeroProyecto = ObtenerPropiedad(proyecto, Properties.Project.PROJ_PROJECTNUMBER); seccion += string.Format(" Nº Proyecto: {0}\n\n", numeroProyecto);
return seccion; }
// ==================================== // SECCIÓN: ESTADÍSTICAS // ==================================== private string GenerarSeccionEstadisticas(Project proyecto) { int totalPaginas = 0; int totalFunciones = 0; int totalDispositivos = 0; int totalConexiones = 0;
foreach (Page pagina in proyecto.Pages) { totalPaginas++; totalFunciones += pagina.Functions.Length; totalDispositivos += pagina.Devices.Length;
foreach (Function funcion in pagina.Functions) { totalConexiones += funcion.Connections.Length; } }
string seccion = "ESTADÍSTICAS:\n"; seccion += "----------------------------------------\n"; seccion += string.Format(" Total de páginas: {0,6}\n", totalPaginas); seccion += string.Format(" Total de funciones: {0,6}\n", totalFunciones); seccion += string.Format(" Total de dispositivos: {0,6}\n", totalDispositivos); seccion += string.Format(" Total de conexiones: {0,6}\n", totalConexiones);
if (totalPaginas > 0) { double promFunciones = (double)totalFunciones / totalPaginas; double promDispositivos = (double)totalDispositivos / totalPaginas;
seccion += "\n Promedios por página:\n"; seccion += string.Format(" Funciones: {0,6:F2}\n", promFunciones); seccion += string.Format(" Dispositivos: {0,6:F2}\n", promDispositivos); }
seccion += "\n"; return seccion; }
// ==================================== // SECCIÓN: ANÁLISIS DE PÁGINAS // ==================================== private string GenerarSeccionPaginas(Project proyecto) { string seccion = "ANÁLISIS DE PÁGINAS:\n"; seccion += "----------------------------------------\n";
Page[] paginas = proyecto.Pages;
// Mostrar primeras 5 y últimas 5 int maxMostrar = Math.Min(5, paginas.Length);
for (int i = 0; i < maxMostrar; i++) { Page pagina = paginas[i]; seccion += string.Format(" {0,3}. {1,-30} | Func: {2,3} | Dev: {3,3}\n", pagina.PageNumber, TruncarTexto(pagina.Name, 30), pagina.Functions.Length, pagina.Devices.Length); }
if (paginas.Length > 10) { seccion += string.Format(" ... ({0} páginas intermedias omitidas)\n", paginas.Length - 10);
for (int i = paginas.Length - 5; i < paginas.Length; i++) { Page pagina = paginas[i]; seccion += string.Format(" {0,3}. {1,-30} | Func: {2,3} | Dev: {3,3}\n", pagina.PageNumber, TruncarTexto(pagina.Name, 30), pagina.Functions.Length, pagina.Devices.Length); } } else if (paginas.Length > 5) { for (int i = maxMostrar; i < paginas.Length; i++) { Page pagina = paginas[i]; seccion += string.Format(" {0,3}. {1,-30} | Func: {2,3} | Dev: {3,3}\n", pagina.PageNumber, TruncarTexto(pagina.Name, 30), pagina.Functions.Length, pagina.Devices.Length); } }
seccion += "\n"; return seccion; }
// ==================================== // SECCIÓN: PROBLEMAS DETECTADOS // ==================================== private string GenerarSeccionProblemas(Project proyecto) { List<string> problemas = new List<string>();
// 1. Verificar páginas vacías int paginasVacias = 0; foreach (Page pagina in proyecto.Pages) { if (pagina.Functions.Length == 0 && pagina.Devices.Length == 0) { paginasVacias++; } }
if (paginasVacias > 0) { problemas.Add(string.Format("Hay {0} página(s) vacía(s)", paginasVacias)); }
// 2. Verificar descripción del proyecto if (string.IsNullOrEmpty(proyecto.ProjectDescription)) { problemas.Add("El proyecto no tiene descripción"); }
// 3. Verificar propiedades básicas string empresa = ObtenerPropiedad(proyecto, Properties.Project.PROJ_COMPANYNAME); if (empresa == "N/A") { problemas.Add("No se ha especificado el nombre de la empresa"); }
string cliente = ObtenerPropiedad(proyecto, Properties.Project.PROJ_CUSTOMER); if (cliente == "N/A") { problemas.Add("No se ha especificado el cliente"); }
// Generar sección string seccion = "PROBLEMAS DETECTADOS:\n"; seccion += "----------------------------------------\n";
if (problemas.Count == 0) { seccion += " ✓ No se detectaron problemas\n"; } else { foreach (string problema in problemas) { seccion += string.Format(" ⚠ {0}\n", problema); } }
seccion += "\n"; return seccion; }
// ==================================== // SECCIÓN: CONCLUSIÓN // ==================================== private string GenerarSeccionConclusion(Project proyecto) { string seccion = "CONCLUSIÓN:\n"; seccion += "========================================\n";
int totalFunciones = 0; foreach (Page pagina in proyecto.Pages) { totalFunciones += pagina.Functions.Length; }
if (totalFunciones == 0) { seccion += "⚠ El proyecto está VACÍO\n"; } else if (totalFunciones < 10) { seccion += "✓ El proyecto es muy PEQUEÑO\n"; } else if (totalFunciones < 100) { seccion += "✓ El proyecto tiene tamaño MEDIANO\n"; } else { seccion += "✓ El proyecto es GRANDE\n"; }
seccion += "\nValidación completada correctamente.\n"; seccion += "========================================\n";
return seccion; }
// ==================================== // UTILIDADES // ==================================== private string ObtenerPropiedad(Project proyecto, int propertyId, string valorPorDefecto = "N/A") { try { AnyPropertyId propId = new AnyPropertyId(propertyId);
if (!proyecto.Properties.ExistsProperty(propId)) { return valorPorDefecto; }
string valor = proyecto.Properties[propId].ToString();
if (string.IsNullOrWhiteSpace(valor)) { return valorPorDefecto; }
return valor; } catch { return valorPorDefecto; } }
private string TruncarTexto(string texto, int maxLongitud) { if (string.IsNullOrEmpty(texto)) return "";
if (texto.Length <= maxLongitud) return texto;
return texto.Substring(0, maxLongitud - 3) + "..."; }}🔍 Deep Dive: Conceptos avanzados
Sección titulada «🔍 Deep Dive: Conceptos avanzados»Properties vs propiedades directas
Sección titulada «Properties vs propiedades directas»// Propiedades directas (más simple)string nombre = proyecto.ProjectName; // Acceso directo
// Properties (más flexible, más propiedades)AnyPropertyId propId = new AnyPropertyId(Properties.Project.PROJ_COMPANYNAME);string empresa = proyecto.Properties[propId].ToString();Cuándo usar cada una:
- Propiedades directas: Para datos básicos siempre disponibles
- Properties: Para propiedades específicas de EPLAN, configurables
SelectionSet.LockSelectionByDefault
Sección titulada «SelectionSet.LockSelectionByDefault»SelectionSet sel = new SelectionSet();sel.LockSelectionByDefault = false; // No bloqueartrue: Bloquea objetos al seleccionarlos (evita modificaciones)false: No bloquea (solo lectura, más seguro para scripts)
Recomendación: Usa false para scripts de lectura/análisis.
📝 Resumen
Sección titulada «📝 Resumen»En este capítulo aprendiste:
- ✅ Atributo [Start]: Punto de entrada del script
- ✅ Estructura de script: Template completo recomendado
- ✅ Obtener proyecto: SelectionSet y GetSelectedProjects()
- ✅ Leer propiedades: Directas y mediante Properties
- ✅ Contar elementos: Páginas, funciones, dispositivos
- ✅ Mostrar mensajes: BaseException con tres niveles
- ✅ Manejo de errores: Específicos de EPLAN API
- ✅ Proyecto completo: Validador inteligente funcional
Conceptos clave:
- Todo script necesita
[Start]para ejecutarse - SelectionSet es la forma estándar de obtener el proyecto actual
- Siempre valida que el proyecto exista y sea válido
- BaseException es la forma correcta de mostrar mensajes en EPLAN
- Properties da acceso a configuraciones específicas de EPLAN
🔗 Conexiones
Sección titulada «🔗 Conexiones»⬅️ Capítulo anterior
Sección titulada «⬅️ Capítulo anterior»Capítulo 12: Arquitectura de EPLAN API
➡️ Próximo capítulo
Sección titulada «➡️ Próximo capítulo»Capítulo 14: ActionCallingContext
En el próximo capítulo aprenderás a pasar parámetros a scripts, hacer scripts parametrizables desde la GUI de EPLAN, y crear herramientas más flexibles y reutilizables.
📚 Recursos adicionales
Sección titulada «📚 Recursos adicionales»- 📖 EPLAN API Documentation:
EplanAPI.chm - 📖 Project Class: Sección DataModel
- 📖 Properties: Lista completa de propiedades disponibles
- 💻 Código completo:
code/cap-13/
❓ Preguntas frecuentes
Sección titulada «❓ Preguntas frecuentes»P: ¿Puedo tener múltiples métodos con [Start]?
Sección titulada «P: ¿Puedo tener múltiples métodos con [Start]?»R: No. Solo puedes tener UN método [Start] por archivo de script. EPLAN no sabría cuál ejecutar.
P: ¿El método [Start] tiene que llamarse “Ejecutar”?
Sección titulada «P: ¿El método [Start] tiene que llamarse “Ejecutar”?»R: No. Puede llamarse como quieras: Run(), Main(), Procesar(), etc. Lo importante es el atributo [Start].
P: ¿Qué pasa si no hay proyecto abierto?
Sección titulada «P: ¿Qué pasa si no hay proyecto abierto?»R: GetSelectedProjects() devuelve un array vacío (Length == 0). Siempre valida esto antes de continuar.
P: ¿BaseException realmente lanza una excepción?
Sección titulada «P: ¿BaseException realmente lanza una excepción?»R: No, es un nombre confuso. BaseException es solo la clase de EPLAN para mostrar mensajes. No lanza excepciones reales (de ahí FixMessage() para mostrarla).
P: ¿Puedo modificar el proyecto en un script?
Sección titulada «P: ¿Puedo modificar el proyecto en un script?»R: Sí, pero debes tener cuidado. Este capítulo se enfoca en lectura. La modificación la veremos en capítulos posteriores.
P: ¿Los scripts se compilan?
Sección titulada «P: ¿Los scripts se compilan?»R: EPLAN los compila automáticamente al ejecutarlos. Si hay errores de sintaxis, EPLAN lo indicará.
📋 Checklist de completitud
Sección titulada «📋 Checklist de completitud»Antes de pasar al siguiente capítulo, asegúrate de:
- Entender qué es
[Start]y por qué es necesario - Poder obtener el proyecto actual con SelectionSet
- Saber leer propiedades básicas (ProjectName, etc.)
- Poder acceder a Properties con AnyPropertyId
- Saber contar páginas, funciones y dispositivos
- Usar BaseException para mostrar mensajes
- Validar precondiciones antes de procesar
- Haber ejecutado el ValidadorProyecto completo
- (Opcional) Modificar el validador con tus propias mejoras
¡Felicitaciones! Has creado tu primer script EPLAN funcional completo. 🎉
Ya puedes leer información de proyectos, validar datos, y generar reportes profesionales.
¿Listo para hacer scripts parametrizables? ¡Vamos al Capítulo 14! 🚀
Última actualización: Enero 2025
Tiempo de lectura estimado: 70-80 minutos
Código de ejemplo: code/cap-13/
📂 Código del Capítulo
Sección titulada «📂 Código del Capítulo»Todos los scripts de este capítulo están disponibles en GitHub:
Los scripts son 100% funcionales y usan únicamente APIs gratuitas de EPLAN.
🔓 Desbloquea el Contenido Completo
¿Te gustó este capítulo? Hay 25 capítulos más esperándote con:
- ✅ Scripts profesionales completos
- ✅ Casos de estudio reales
- ✅ Suite de automatización integrada
- ✅ Ahorra 80-95% de tiempo en tareas repetitivas