Pues eso… este post es para tener actualizada la utilidad CrearClaseTabla que en su día (allá por 2004) creé para generar o crear clases para acceder a una base de datos de SQL Server o de Access.
La idea de esta utilidad (la aplicación y la DLL que es la que hace el trabajo) es crear clases de Visual Basic o C# de cada tabla de la base de datos, con idea de facilitar el acceso por código a esas tablas.
En la última actualización de hoy 1 de octubre de 2022 se contempla, entre otras cosas, la definición de variables asignadas sin indicar el tipo (inferencia de tipos) además de convertir adecuadamente las conversiones de tipo de Visual Basic a C# (aunque en el código solo uso CInt).
Nota: He creado el proyecto para .NET 6.0 (Windows) y está disponible en GitHub: gsCrearClasesTablas. Por ahora el código es el mismo en este nuevo proyecto como en el que referencio en este post/artículo que es para .NET Framework 4.8.1
El código «base» que utilizo es el que yo uso con Visual Basic y la clase CrearClase apoyada de ConvLag se encarga de generar el código de Visual Basic o el de C#.
Por ejemplo, el código que te muestro primero, en el generador de clases lo defino como te muestro en el segundo bloque de código:
Este es el código en que me he basado:
cmd.Transaction = tran
cmd.ExecuteNonQuery()
' Si llega aquí es que todo fue bien,
' por tanto, llamamos al método Commit.
tran.Commit()
msg = "Se ha actualizado el Cliente correctamente."
Catch ex AsException
msg = $"ERROR: {ex.Message}"
' Si hay error, deshacemos lo que se haya hecho.
Try
If tran IsNotNothingThen
tran.Rollback()
EndIf
Catch ex2 AsException
msg = $" (ERROR RollBack: {ex.Message})"
EndTry
Finally
con.Close()
EndTry
EndUsing
Return msg
Este es el código interno que uso en el conversor (el método generarClase): En los comentarios está el código mostrado antes y el equivalente para generar el código de VB o de C#.
sb.AppendLine()
' cmd.Transaction = tran
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("cmd.Transaction", "tran"), vbCrLf)
' cmd.ExecuteNonQuery()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("cmd.ExecuteNonQuery()"), vbCrLf)
sb.AppendLine()
' ' Si llega aquí es que todo fue bien,
' ' por tanto, llamamos al método Commit
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" Si llega aquí es que todo fue bien,"), vbCrLf)
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" por tanto, llamamos al método Commit."), vbCrLf)
' tran.Commit()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("tran.Commit()"), vbCrLf)
sb.AppendLine()
' msg = "Se ha actualizado el Cliente correctamente."
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", """Se ha actualizado un " & nombreClase & " correctamente."""), vbCrLf)
sb.AppendLine()
' Catch ex As Exception
sb.AppendFormat(" {0}{1}", ConvLang.Catch("ex", "Exception"), vbCrLf)
' msg = $"ERROR: {ex.Message}"
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", "$""ERROR: {ex.Message}"""), vbCrLf)
' ' Si hay error, deshacemos lo que se haya hecho
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" Si hay error, deshacemos lo que se haya hecho."), vbCrLf)
' Try
sb.AppendFormat(" {0}{1}", ConvLang.Try(), vbCrLf)
' Añadir comprobación de nulo en el objeto tran (17-abr-21)
' If tran IsNot Nothing Then
sb.AppendFormat(" {0}{1}", ConvLang.If("tran", "IsNot", "Nothing"), vbCrLf)
' tran.Rollback()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("tran.Rollback()"), vbCrLf)
' End If
sb.AppendFormat(" {0}{1}", ConvLang.EndIf, vbCrLf)
' Catch ex2 As Exception
sb.AppendFormat(" {0}{1}", ConvLang.Catch("ex2", "Exception"), vbCrLf)
' msg &= $" (ERROR RollBack: {ex.Message})"
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", "$""ERROR RollBack: {ex2.Message}"""), vbCrLf)
' End Try
sb.AppendFormat(" {0}{1}", ConvLang.EndTry(), vbCrLf)
sb.AppendLine()
sb.AppendFormat(" {0}{1}", ConvLang.Finally, vbCrLf)
' If Not (con is nothing) then
sb.AppendFormat(" {0}{1}", ConvLang.If("", "Not", "(con Is Nothing)"), vbCrLf)
' con.Close()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("con.Close()"), vbCrLf)
' End If
sb.AppendFormat(" {0}{1}", ConvLang.EndIf, vbCrLf)
' End Try
sb.AppendFormat(" {0}{1}", ConvLang.EndTry(), vbCrLf)
sb.AppendLine()
' End Using
sb.AppendFormat(" {0}{1}", ConvLang.EndUsing(), vbCrLf)
sb.AppendLine()
' Return msg
sb.AppendFormat(" {0}{1}", ConvLang.Return("msg"), vbCrLf)
Y el código generado de Visual Basic sería como te he mostrado arriba y el de C# sería más o menos este:
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
// Si llega aquí es que todo fue bien,// por tanto, llamamos al método Commit.
tran.Commit();
msg = "Se ha actualizado un Producto correctamente.";
}catch(Exception ex){
msg = $"ERROR: {ex.Message}";
// Si hay error, deshacemos lo que se haya hecho.try{
if(tran != null ){
tran.Rollback();
}
}catch(Exception ex2){
msg = $"ERROR RollBack: {ex2.Message}";
}
finally{
if( ! (con == null )){
con.Close();
}
}
}
return msg;
Como ves, no está bien formateado, (es el código generado directamente) pero si lo pegas en Visual Studio te lo formateará bien y lo coloreará mejor 😉
Y para muestra, ese trozo de código en un fichero abierto en Visual Studio 2022: (Aunque todo hay que decirlo, en VB lo formatea bien, aunque solo sea un fichero abierto directamente (sin formar parte de ningún proyecto) mientras que en C# le he tenido casi que dar el formato manualmente, en fin…)
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
// Si llega aquí es que todo fue bien,
// por tanto, llamamos al método Commit.
tran.Commit();
msg = "Se ha actualizado un Producto correctamente.";
}
catch(Exception ex)
{
msg = $"ERROR: {ex.Message}";
// Si hay error, deshacemos lo que se haya hecho.
try
{
if (tran != null)
{
tran.Rollback();
}
}
catch(Exception ex2)
{
msg = $"ERROR RollBack: {ex2.Message}";
}
finally
{
if (!(con == null))
{
con.Close();
}
}
}
Pero la idea es que te quedes con lo que la clase hace.
También es cierto que yo suelo generar el código para Visual Basic y es lo que realmente he probado más, hoy he estado viendo cómo lo generaría para C# y he estado haciendo algunas correcciones (que he indicado en el fichero Revisiones.md publicado con GitHub).
Una captura de la utilidad tal como la tengo a día 1 de octubre de 2022.
Figura 1. La utilidad en funcionamiento a día de hoy 1 de octubre de 2022
Y esto es todo amigo (o amiga), ya sabes, si quieres participar en el proyecto para mejorarlo, puedes hacerlo, creo que en algún sitio indico cómo avisarme de los errores que encuentres y cómo actualizar el fichero Revisiones.txt que ahora es Revisiones.md.
Y si quieres usarlo sin más aportaciones, estaría bien que hicieras una pequeña aportación monetaria en PayPal (no es obligatorio, pero es de agradecer).
En breve publicaré en GitHub el ejecutable compilado con .NET Framework 4.8.1.
Por cierto, en el proyecto (los dos) he incluido un fichero de nombre seguro (strong name) para firmar los ensamblados, ese fichero (elGuille_compartido.snk) lo puedes usar «libremente» (ya sabes todo está con la licencia MIT) para firmar los ensamblados con nombre seguro.
Espero que te sirva de utilidad.
Nos vemos. Guillermo
P.S. Sería interesante convertir el proyecto para .NET 6 (o 7) y también usando el código completamente en C#. Actualmente está creado para usar con .NET Framework 4.8.1 y escrito enteramente en Visual Basic.
P.S.2 Ya está creado el proyecto para .NET 6.0 (net6.0-windows) y publicado en GitHub (gsCrearClasesTablas).
gsNotas.Mobile multiplataforma (versiones 2.1.0.4 y 2.1.0.5)
Nota: Esta es la página para la última versión publicada de gsNotas multiplataforma. Si estás buscando la versión 2.0.0.33 sigue el enlace.
En la última actualización de ayer 26 de mayo de 2021 (la terminé de compilar, etc. ayer día 26 pero hoy 27 de mayo es cuando la hago público y pondré el código fuente de esta última release en GitHub) ha habido unos cambios con respecto a la última versión, entre ellos que está disponible para Windows UWP (Universal Windows Platform) y estará publicada en la Microsoft Store cuando este sitio tenga el certificado de seguridad, que aún no tiene por aquello del cambio de proveedor de hosting y el latazo de los cambios de registro de los dominios, etc.).
El nombre cambia a gsNotas (gsNotas.Mobile) pero que cada plataforma tendrá el suyo propio: gsNotas.Android para Android, gsNotas.UWP para la plataforma universal de Windows y gsNotas.iOS para el iPhone (en teoría para cualquier dispositivo iOS).
La versión para iOS (iPhone) ya he podido hacerla funcionar en el móvil que tengo: iPhone 7 plus. Aún no puedo crear la aplicación para la App Store de Apple porque necesito un Mac con la última versión de Xcode, y el Mac que tengo actualmente a mi disposición (a través de conexión remota), el de mi nuera Olena, no tiene la última versión del Mac OS por tanto no puedo tener el último Xcode. Aunque me ha comentado mi hijo David que está por actualizarlo, aunque esa última versión del MacOS no es de su agrado… se ve que tiene fallos…
La versión para iOS (iPhone, etc.) tendrá que esperar, ya que había problemas entre Microsoft y Apple con el tema de los certificados, etc., y parece ser que ya lo han solucionado, el problema es que para poder crear el paquete de instalación necesito un Mac con la última versión de Xcode y el que tengo disponible es una versión del iOS que no soporta esa última versión de Xcode, así que… a esperar o a ver si un alma caritativa me ofrece un Mac de forma remota con la última versión del iOS.
Novedades en esta versión (2.1.0.4~2.1.0.5)
v2.1.0.5 (27-mayo-2021)
Aparte de poder compilar y probar la versión para iOS en un iPhone 7 Plus, he añadido código para que los Placeholder (el texto mostrado como indicador de qué se espera que escribas) se vean también en modo oscuro (en modo light/claro se veían bien, pero desaparecían en modo dark/oscuro). Y es que yo suelo tener mi móvil (de Android) en modo oscuro, más que nada por el tema del ahorro de batería y normalmente no se veían esos placeholders salvo que cambiara a modo claro (quitando el ahorro extremo de batería).
Novedades cosméticas
La mayoría de estas novedades son más bien cosméticas, es decir, un pequeño lavado de cara, pero no en plan grande, si no, de apoco que dirían mis colegas del otro lado del charco; como por ejemplo, dividir todas las opciones que antes se mostraban en la pantalla de inicio en dos pantallas (ahora pondré las capturas). De esta forma, las más usuales estarán en la primera pantalla y el resto en la otra.
Pero también hay novedades en cuanto a la funcionalidad.
Novedades funcionales
El otro día (ya no recuerdo qué día) me cambié de compañía telefónica en el móvil, tenía Digi Mobil y me cambié a Amena. El cambio fue porque yo vivo en el campo y aquí no hay cobertura telefónica, esto es como un agujero negro para las compañías telefónicas, solo tengo acceso por medio del Wi-Fi, pero no porque una compañía telefónica lo ofrezca, no, para eso también es un agujero negro, es porque un colega tiene un repetidor de señal que trae desde el pueblo (Nerja) hasta aquí los montes (Río de la Miel), y hasta ahora toda la comunicación era por medio de Internet. Pero los de Orange ofrecen un servicio llamado Llamadas por Wi-Fi, y como Orange es caro (para mí) me decidí por Amena que tiene una tarifa aceptable. Retomamos la historia, sin tantas historias: Y en ese transcurso del cambio de compañía, perdí la conexión a Internet mientras estaba en el pueblo, como esta utilidad la suelo usar para tomar notas, quise abrirla para consultar algo, y resulta que me decía que no había conexión a Internet, así que, decidí usar las notas locales, pero… ¡No me las mostraba! ¿Por qué? Porque no había conexión a Internet… ¿¿¿??? Así que… me dije a mí mismo: A ver Guille… si las notas locales están para usarlas cuando no hay conexión y no se pueden usar cuando no tienes conexión… ¿para qué puñetas sirven? Y me respondí: ¡Poh e verdá! (yo es que conmigo mismo hablo así)
Así que… esa es una de las novedades funcionales de la nueva versión: ¡Que se puede trabajar de forma local aunque no estés logueado!
Por tanto, y para que quede evidente, en la pantalla de LOGIN he añadido un botón para conectar de forma local: Acceder sin conexión.
La segunda novedad importante es que las notas permiten más de 2048 caracteres. Por ahora no está accesible a todo el mundo, lo siento, solo para los que hayan hecho donativos de 25€ o más. Pero no te preocupes, las notas se pueden seguir guardando aunque no guarde más de 2048 caracteres. En realidad, la aplicación usa dos tablas de notas: Notas y NotasMax. En la primera (Notas) usa un campo (Texto) de tipo nchar(2048), lo iba a cambiar a nchar(4000) que es el máximo permitido para nchar, pero para ello tenía que eliminar todos los datos que ya había (recrear la tabla) y… pues como que no era plan. Así que, he creado la segunda tabla (NotasMax) en la que el campo Texto es de nvarchar(Max), es decir, con capacidad de 2GB máximo que viene a ser de 1GB de caracteres. He probado el rendimiento tanto en Android como en Windows y va bien.
Como te he dicho antes, esa otra tabla solo está accesible si has donado 25€ o más. Si no es así, no puedes seleccionar cuál de las dos tablas usar y por tanto, usará la tabla normal de 2048 caracteres máximo, que creo que para notas normales es más que suficiente. La tabla que estás usando se muestra en la barra de estatus (abajo). Si usas las notas locales, la capacidad será la que da SQLite, que la verdad no sé cuál es. Sigue este enlace si quieres leer sobre el tema (aunque a mí no me queda claro cuántos caracteres se puede tener en un campo de texto).
Otros de los cambios, que serían más bien estéticos, es el coloreado de los textos y demás. Lo he probado con el tema claro y oscuro de mi móvil Android y va bien. En el emulador siempre van bien los dos tipos de temas, pero cuando la uso desde el móvil «de verdad» no siempre se muestran todos los textos. En Windows también va bien con el tema oscuro, aunque en realidad solo afecta a los campos de edición, el resto se muestra igual con los dos tipos de temas.
Con la versión 2.1.0.5 ya está solucionado lo de los Placeholder en Android (en iOS y UWP no era problema).
Aunque en Android el texto de ayuda en los campos sigue sin mostrarse cuando se usa el tema oscuro, es decir lo que se indica en Placeholder. Algún día espero poder solucionarlo. 🙂
La configuración la guardo ahora en un fichero de texto interno (en Environment.SpecialFolder.LocalApplicationData) ya que al guardarlo como hasta ahora en Application.Current.Properties, no siempre recuperaba esos valores… Lo mismo es por fallo mío, pero… uno de mis dichos es: Si las cosas no siempre funcionan igual, intenta usar lo que siempre debería funcionar. Por tanto, si has estado usando la versión anterior, puede que los valores de la configuración no te los lea cuando abras por primera vez esta nueva versión.
Cosas diferentes en la app de Android de la de UWP
Aunque no son funcionales, hay un par de cambios entre las app de Android y la de Windows (UWP), y es que en la de Windows (en escritorio que es como la utilizo) la flechita de ir atrás es muy pequeña, así que… he añadido botones para ir atrás que en la aplicación de Android (u otra que no sea de UWP) no se muestran. Esos botones solo sirven para ir a la página anterior, por tanto, no son realmente funcionales si no, más bien estéticos.
Respecto a esto, el botón de añadir nueva nota, en Android siempre se mostraba (+Nota), pero en UWP se mostraba el menú ese de tres puntitos a la derecha y quedaba como oculto esa posibilidad de agregar una nueva nota, así que… he optado por poner un botón bien visible para que quede claro si se quiere añadir una nueva nota qué es lo que hay que hacer.
Y creo que esto es todo. Ahora te pondré un par de capturas tanto de la app de Android (en dispositivo real) como de UWP en la versión escritorio.
Descargas de las aplicaciones
Comentarte que a día de hoy 27 de mayo de 2021, la aplicación de UWP en Mocrosoft Store aún no está disponible, ya que me la rechazan porque el acceso a la política de privacidad no se muestra de forma correcta. Y esto es porque al acceder a este blog que aún no tiene el certificado de seguridad para usar HTTPS, pues… eso… dicen que nones. Cuando esté disponbible pondré el enlace a la tienda. Cambié la url de la política de privacidad y la publiqué… o eso pensé, ya que en realidad estaba aún con la advertencia… así que… esta mañana (7 de junio 2021) le di a publicar en la MS Store y ya está disponible.
Como podrás ver en las capturas (figuras 3 y 6) he puesto un botón por si quieres Hacer un donativo con PayPal que te llevará a la misma página que el enlace anterior. Ese donativo figurará como que es para gsNotas y por tanto te servirá para ir acumulando y acceder a las características de los donadores. 😉 Ya sabes que todo esto es gratis y aunque le dedico bastante tiempo no es que quiera cobrar por ese tiempo… pero ya sabes que de algo hay que vivir… pagar la comida, el alquiler de la casa, los impuestos, la conexión a Internet, etc. Así que… si te sientes generoso y quieres (y puedes hacerlo), ahí está el botón de hacer donativos. Imagina que me quieres invitar a un café o a una chela… pues… ¡ya sabes qué hacer! 😉
Capturas
De Android con el Placeholder solucionado en v2.1.0.5. El texto en gris: Escribe aquí tu comentario antes no se veía cuando estaba seleccionado el terma oscuro. Que aunque en la captura no lo parezca, está usando el tema oscuro.
Figura 9. En Android (tema oscuro aunque no lo parezca) ya se ve el texto de los Placeholders.
De iPhone (iOS)
Figura 8. Captura de la pantalla de inicio en un iPhone 7 Plus.
De Windows (UWP) Escritorio
Figura 1. La página de inicio en Windows (UWP Desktop).Figura 2. La página de acceso (Login) en Windows UWP.Figura 3. Las opciones de configuración en UWP. Puedes ver el botón Volver que no está en Android.
De Android (dispositivo Pixel 4a)
Figura 4. La página de inicio en dispositivo Android (Pixel 4a).Figura 5. La página de Otras opcione en dispositivo Android (Pixel 4a).Figura 6. La página de configuración en dispositivo Android (Pixel 4a).Figura 7. La página de acceso (Login) en dispositivo Android (Pixel 4a).
Nota: Esta es la versión 2.0.0.33 publicada el 31 de diciembre de 2021. A fecha de hoy 27 de mayo de 2021 está la versión 2.1.0.4 que estará en el mismo post en el que estaba la anterior (por el tema de los enlaces) pero el contenido es diferente, ya que ahí te cuento las novedades añadidas recientemente (y será la que mantenga la última versión hasta que decida cambiar… 🙂 )
gsNotasNET multiplataforma
Aunque el nombre sea gsNotasNET.Android es una aplicación para dispositivos móviles (móviles y tabletas) pensada (inicialmente) para usar con Android, pero que después le he añadido proyectos para iOS (iPhone y iPad de Apple) y UWP (Universal Windows Plataform, en teoría para móviles, tabletas y Start de Windows 10).
Pero que a día de hoy (31-dic-2020) no he sido capaz de hacerlos funcionar en esos dos últimos, la aplicación, que accede a una base de datos externa de SQL Server, además de una local creada con SQL Lite, por ahora solo funciona correctamente en dispositivos Android.
Actualmente está publicada la versión 2.0.0.33, el paquete para Android lo puedes descargar desde esta release: gsNotasNET.Android v2.0.0.33
En distintas entradas de este blog he ido publicando lo que cada una de las releases (versiones) hace.
A continuación te pondré unos enlaces a esas distintas versiones para que vayas viéndolas. Empezaré por la más reciente.
Todas estas versiones están basadas en un intento de hacer una aplicación similar a gsNotasNETF.
Sobre el uso de la aplicación para dispositivos móviles en iOS y UWP
Como digo en el proyecto de gsNotasNET.Android publicado en GitHub, por ahora la aplicación que usa la base de datos de SQL Server alojada en un servidor en la nube solo funciona (y está operativa al 100%) en dispostiivos Android, los proyectos para iOS (iPhone, iPad) y para UWP (Windows 10) no funcionan, el de iOS no he sido capaz de hacerlo funcionar ni siquiera usando Visual Studio 2019 para Mac, y el de Windows 10 (UWP) no lo he podido poner en funcionamiento de forma local en Windows 10 (al intentar probarlo en los emuladores, se quedaba colgado intentando lanzar el dispositivo emulado).
Así que, seguramente crearé un proyecto multiplataforma pero que solamente use las notas en la base local, a ver si es por el acceso a SQL Server por lo que no funciona.
Ya está operativa la base de datos (he eliminado todas las notas de prueba).
Puedes registrarte directamente en la aplicación o mandar un mensaje a coreos.elguille.info@gmail.com indicando tu nombre completo, cuenta de gmail y el password y te añadiré…
Esta es una captura de la aplicación tal como se inicia.
Captura de la aplicación funcionando en un dispositivo (Pixel 4a)
Tendrás que pulsar en Cambiar de Usuario y desde ahí te puedes registrar.
Espero que te guste y si tienes problemas… me lo dices.
He detectado que en un móvil con android antiguo me dio error, pero al instalara la versión 2.0.0.28 ya funcionó bien.
Eso sí, tuve que modificarle el usuario y el código SHA manualmente porque la cuenta de correo estaba mal…
Nota del 10-dic-2020 01:04 GMT+1: La utilidad ha cambiado, para ver los cambios, te recomiendo que o bien los veas en GitHub o en la página de gsNotasNETF.
Nota: Esta es la entrada de esta utilidad, también existe una página con (casi) el mismo nombre para que aparezca en el menú de Utilidades NET>Utilidades con .NET Framework Pulsa aquí para ir a la página gsNotasNETF.
Esta utilidad sirve para escribir y guardar notas, agrupadas en grupos (o si lo prefieres, etiquetas). Cada grupo contendrá un número de notas (por ahora no hay un máximo de notas por grupo, pero si veo que el rendimiento es malo, tendré que limitarlo). Tampoco hay límite de grupos a crear, pero como dije antes, comprobaré el rendimiento y veré si es necesario hacer alguna limitación de número de grupos.
Esta utilidad está definida por un formulario que simplemente sierve de contenedor del control de usuario NotasUC que a su vez utiliza el control de usuario CabeceraNotasUC que es el que se encarga de mantener, guardar y leer la colección con los grupos y notas. El aspecto del control (en tiempo de diseño es el mostrado en la figura 1):
Figura 1. El control NotasUC en tiempo de diseño. Arriba está el control CabeceraNotaUC.
Figura 2. La aplicación de prueba, arriba las notas del grupo seleccionado, abajo el control NotasUC con las notas.
El formato que utiliza el fichero con las notas es lo que yo he llamado formato NotasUC que tiene el siguiente formato:
#Formato NotasUC - v1.0.0.0 - 05-dic-2020
#
# Fichero de Notas con formato NotasUC
#
# Contenido de gsNotasNETF.notasUC.txt
#
# Formato:
# G:Nombre del grupo 1
# Lista de notas del grupo 1, una en cada línea
# GFin: Fin de las notas del grupo 1
# G:Nombre del grupo 2
# Lista de notas del grupo 2, una en cada línea
# GFin: Fin de las notas del grupo 2
#
# Notas:
# No se guardan los grupos o notas que estén en blanco.
# Si la nota tiene estos caracteres, se hará un cambio al guardar el texto:
# Las comillas dobles se guardan como |quot|.
# El signo mayor > se guarda como |gt|.
# El signo mayor < se guarda como |lt|.
# El ampersand & se guarda como |A|.
# Si la cadena empieza con un espacio, se sustituye por |sp|.
# Los cambios de línea '\n\r' (CrLf) se guardan como |NL|.
# Los cambios de línea '\n' (Cr) se guardan como |CR|.
# Los retornos de carro '\r' (Lf) se guardan como |LF|.
# La comprobación se hace en este orden: CrLf, Cr, Lf
# Es para los casos que haya distintos cambios de línea (según el formato del fichero)
#
En GitHub he puesto el código fuente de esta utilidad que se puede usar como biblioteca dinámica para acceder a los dos controles definidos, aunque usando solo NotasUC es suficiente, ya que ahí se hace prácticamente todo el trabajo.
Pues eso… viendo el video de Filip Ekberg sobre los record en C# 9.0 (siempre hay que intentar aprender más) me gustó ver que mientras explicaba el código se veía el código desemsamblado (como lo genera el compilador de .NET) y es usando una herramienta online accesible mediante el enlace a https://sharplab.io/.
Si pones la dirección https://sharplab.io/ en el navegador, te mostrará una ventana con dos paneles.
Con las siguientes capturas te voy explicando un poco cómo configurar el «entorno» de trabajo.
En la figura 1 vemos el entorno ya configurado para usar los compiladores de Roslyn, para eso indicamos master (11 nov 2020) (es la que hay a día de hoy 13 de noviembre) que como ves con más detalle en la figura 2 nos permite seleccionar el «framework» a usar para compilar el código que pongamos en el panel izquierdo.
En la figura 3 puedes ver que se pueden usar los tres lenguajes que se incluyen en .NET, es decir: C#, Visual Basic y F#.
En el panel derecho se muestra el código decompilado, por defecto es en C# (sí, aunque en la izquierda lo escribas con otro lenguaje diferente a C#).
Pero como puedes ver en la figura 4 se puede mostrar de otras formas, eso sí, si quieres ver el código tal como lo trata el compilador, éste será en C#. Las otras opciones son, entre otras,. el código ensamblado IL o incluso en ejecución (Run). Ya es cuestión de ir probando cada una de esas opciones de la figura 4 para ir viendo cómo nos muestra el código.
En la figura 5 puedes ver código de Visual Basic (en el panel izquierdo) y el resultado de compilarlo y mostrarlo en C#.
Pero fíjate que he señalado una clase que (al menos así parece ser) es requerida para poder usar el código de tipo nivel superior, es decir, sin necesidad de crear el método Main, etc.), ya que si quitas ese código te dará error, tal como puedes ver en la figura 7.
Y si te gusta usar el tema oscuro, en la parte inferior derecha (junto a Theme) puedes seleccionar entre Auto, Light y Dark. A mí me ha mostrado el modio claro (Light) cuando lo inicié y ahí abajo me indicaba Auto tal como puedes ver en la figura 1.
Y esto es todo… es cuestión de ir practicando y probar más cosas de esta útil herramienta online.
Figura 1.Figura 2.Figura 3.Figura 4.Figura 5.Figura 6.Figura 7.
Nota del 26-oct-2020 20:59: Esta página estaba originalmente publicada en elguille.info y la he pasado al blog para poder editarla más fácilmente ya que lo que publico en elGuille.info lo hago con un editor de texto normal y corriente… y ¡es un rollo! Por supuesto, esta misma página aparecerá en elGuille.info, así que… no se notará mucho que no está realmente ubicada allí.
NOTA del 24/Oct/2020 Revisión de esta utilidad usando la nueva versión publicada hoy de gsColorearNET en NuGet. He actualizado también la instalación de ClickOnce.
Nota del 12/Sep/2020 Estoy probando la utilidad de colorear en .NET 5.0 Preview 8 y a duras penas ya está operativa… es que el editor de Visual Studio 2019 Preview está aún muy verde para las aplicaciones de Windows Forms para Visual Basic.
El hacerlo con esa versión es para poder depurar el código de la DLL de colorear, ya que en un proyecto de .NET framework no se puede… o yo no sé cómo hacerlo… todo hay que decirlo.
Cuando tenga tiempo publicaré en el blog las cosillas que recomiendo hacer hasta que mejoren el editor/diseñador de WinForms para Visual Basic.
Nota del 11/Sep/2020: Esta nueva versión utiliza la librería de colorear código compilada para .NET Standard 2.0. Esa DLL la he instalado desde el paquete de NuGet que he creado para la DLL gsColorearNET. No he probado el instalador de ClickOnce en otro equipo, así que no sé si será totalmente operativo 😉 Al menos lo es en mi propio equipo… De todas formas, actualizaré el código fuente de la nuevas versión, que aparte de usar esa DLL de colorear, también tiene otros cambios (mejoras) con respecto a la actualización anterior del 9 de septiembre pasado.
El programa principal y la DLL de colorear están compilados con Visual Studio 2019, en el caso de la utilidad (gsColorearCodigo.exe) utilizando el .NET Framework 4.8, y la DLL (gsColorearNET.dll) está compilada para usar .NET Standard 2.0.
Entre otras cosas, esta versión (aparte de las mejoras en gsColorearNET) incluye la opción de «Colorear desde RTF» (ver la Figura 1). Así como algunos cambios en la pestaña de configuración (ver figura 2) y en la ventana de mostrar RTF, que ahora permite cambiar el código RTF y al pulsar en el botón RTF se muestran los cambios realizados.
Figura 1. Colorear desde RTF
Es la opción que en un 99.99% de las veces utilizo para colorear el código ya que me permite copiar el texto de Visual Studio (es lo que se ve detrás de la utilidad) lo pego en la aplicación y al usar esa opción de Colorear desde RTF lo que hace es colorear para HTML usando el código de RTF, es decir, no comprueba las palabras clave, etc., para generar el código HTML a usar en una página WEB.
Figura 2. Pestaña de opciones
Instalar gsColorearCodigo (y el código fuente)
Para instalar la utilidad puedes hacerlo de dos formas:
Usando el ZIP que hay más abajo, pero tendrás que compilarlo ya que el ejecutable no se incluye, solo el código fuente para Visual Basic.
Instalándolo por medio de ClickOnce (recomendado), ya que así podrás recibir notificaciones cuando haya alguna nueva versión e instalarla automáticamente.
En cualquier caso, lo instales directamente o por medio de ClickOnce, desde la ventana de Acerca de puedes comprobar si hay nuevas versiones del programa o también mirando esta página, que al fin y al cabo es la que usa el programa para saber si hay nuevas versiones (o actualizaciones).
Nota: En realidad la página que mira para ver si hay nuevas actualizaciones es la anterior (la original creada con .NET 2.0) pero he puesto allí la misma versión que en esta… y cuando actualice nuevamente la utilidad, cambiaré el enlace para que mire esta página. Esto es así porque esta página la he publicado después de compilar y crear el instalador.
Más abajo tienes los enlaces con el código completo para Visual Basic usando una solución de Visual Studio 2019 con .NET 4.8 en el que se hace referencia a la DLL gsColorearNET instalada con el package de NuGet.
Espero que te sea de utilidad
Nos vemos. Guillermo
El ZIP con el código completo
El código tanto de la aplicación gsColorearCodigo para .NET Framework 4.8 como de la DLL gsColorearNET para .NET Standard 2.0 lo puedes descargar desde GitHub
Nota del 26-oct-2020 20:45: Esta página estaba originalmente publicada en elguille.info y la he pasado al blog para poder editarla más fácilmente ya que lo que publico en elGuille.info lo hago con un editor de texto normal y corriente… y ¡es un rollo! Por supuesto, esta misma página aparecerá en elGuille.info, así que… no se notará mucho que no está realmente ubicada allí.
Esta es una biblioteca (DLL) compilada para .NET Standard 2.0 y así poder usarla en cualquier plataforma que lo acepte, incluidos los proyectos de .NET Framework 4.6.1 a 4.8 y de .NET Core 2.0 a .NET 5.0, entre otros… Si quieres ver dónde se pueden usar las DLL compiladas con .NET Standard 2.0 mira este enlace: .NET Standard
Últimas actualizaciones
Nota del 24/Oct/2020 (v1.0.0.14) He actualizado tanto el paquete de NuGet como el código en GitHub. También la utilidad de gsColorearCodigo para que use esta nueva versión.
Los cambios principales son para no eliminar las líneas en blanco que haya en el código. Esto era porque la función Split original de Visual Basic no elimina las líneas en blanco. Además de usar vbCr en lugar de vbCrLf al examinar cada línea y crear nuevas separaciones, ya que al añadir vbCrLf añadía una línea extra en blanco.
Aunque últimamente se me ha dado el problema que no todos los ficheros tienen el mismo tipo de retorno de carro. Por tanto he tenido que comprobar antes de hacer el Split qué tipo de retorno de carro tiene: vbCrLf o vbCr o vbLf.
Nota del 16/Sep/2020 (v1.0.0.7) He actualizado tanto el paquete de NuGet como el código en GitHub. También la utilidad de gsColorearCodigo para que use esta nueva versión.
Los cambios principales son para no eliminar las líneas en blanco que haya en el código. Esto era porque la función Split original de Visual Basic no elimina las líneas en blanco. Además de usar vbCr en lugar de vbCrLf al examinar cada línea y crear nuevas separaciones, ya que al añadir vbCrLf añadía una línea extra en blanco.
Nota del 13/Sep/2020 (v1.0.0.6) He actualizado tanto el paquete de NuGet como el código en GitHub. También la utilidad de gsColorearCodigo para que use esta nueva versión.
Con fecha del 12 de septiembre de 2020 he creado un repositorio en gitHub para el código de gsColorearNET.
De ahí puedes descargar el proyecto completo a excepción del fichero de nombre seguro (.snk)
Estoy probando la utilidad de colorear en .NET 5.0 Preview 8 y a duras penas ya está operativa… es que el editor de Visual Studio 2019 Preview está aún muy verde para las aplicaciones de Windows Forms para Visual Basic (y para C# tampoco está muy fino).
El hacerlo con esa versión es para poder depurar el código de la DLL de colorear, ya que en un proyecto de .NET framework no se puede… o yo no sé cómo hacerlo… todo hay que decirlo.
Cuando tenga tiempo publicaré en el blog las cosillas que recomiendo hacer hasta que mejoren el editor/diseñador de WinForms para Visual Basic.
NOTA: Aún la estoy probando desde NuGet ya que usándola como proyecto compila y funciona bien, pero al publicar el paquete en NuGet (aquí tienes el enlace: gsColorearNET en NuGet), no me encuentra los lenguajes de las palabras clave. ¡Esto último ya está solucionado con el paquete 1.0.0.1!
Por ahora no te voy a poner el código fuente, en realidad ha cambiado poco desde lo que publiqué anteayer, y como lo que quiero añadir o corregir aún lo tengo que hacer… pues… habrá que esperar unos días a que lo tenga terminado y así ya la publico de forma, que salvo que haya algunos fallos, no tenga que modificarla en algún tiempo.
Lo que sí haré es actualizar el paquete de NuGet con las correcciones que le vaya haciendo.
Sobre el uso de un proyecto DLL de .NET Standard con un proyecto de .NET Framework
Probando el código de gsColorearCodigo usando el .NET 4.8 en Visual Studio 2019 con el proyecto de gsColorearNET usando .NET Standard 2.0, al producirse un error (o sin que se produzca) y querer depurar en el código de la DLL, el VS no me dejaba… Así que… para comprobar porqué fallaba el penúltimo cambio que le hice, tuve que abrir un proyecto de .NET 5.0 (Preview 8) usando el Visual Studio Preview, y en ese entorno si pude depurar y averiguar cuál era el fallo… que después resultó ser algo trivial, pero…
Así qué… ya sabes… si mezclas… no debugues… 😉
Usar código de Visual Basic en .NET Standard
Otra de las cosillas que me he encontrado a la hora de poder compilar el código del proyecto gsColorear para .NET Framework (ya hay que ir haciendo las aclaraciones de que no todo es simplemtente .NET, porque tenemos .NET Framework, .NET Core, .NET Standard y… casi ya… también simplemente .NET refiriéndose a .NET Core) es la definición de algunas de las funciones del ensamblado Microsoft.VisualBasic en concreto de la clase Strings que no están definidas en .NET Standard 2.0, tal como: Len, Left, Mid, Right, Split, InStr y Trim.
Para no tener que cambiar todo el código que usaba esas funciones (recuerda que el código de colorear lo hice sobre el año 2001, sí, con Visual Basic 6.0, después en diciembre del 2002 lo pasé a la beta de Visual Studio .NET, la aplicación de aquél entonces era HTMLColorCode, aunque debo tener otra aplicación llamada gsEditor… el tiempo no perdona… por la memoria…) así que… me he creado una clase en la que he definido esas funciones, que (seguramente) pueden mejorarse, pero… así las he programado / codificado / como prefieras decirlo.
Y te pego aquí el código por si te puede ser de ayuda.
'------------------------------------------------------------------------------' Clase definida en la biblioteca para .NET Standard 2.0 (10/Sep/20)' Basada en gsColorear y gsColorearCore'' VBCompat (10/Sep/20)' Clase con instrucciones para compatibilidad con .NET Standard 2.0'' Declaro algunas funciones de Microsoft.VisualBasic.Strings' que no están en .NET Standard 2.0'' (c) Guillermo (elGuille) Som, 2020'------------------------------------------------------------------------------OptionStrictOnOptionInferOnImports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
'Imports System.DataPublicClassVBCompat'''<summary>''' Devuelve los caracteres desde la posición (en base 1)''' hasta el final.'''</summary>'''<param name="str"></param>'''<param name="pos"></param>PublicSharedFunction Mid(str AsString, pos AsInteger) AsStringReturn str.Substring(pos - 1)
EndFunction'''<summary>''' Devuelve la cadena desde la posición indicada con len caracteres.''' La posición del primer carácter es el 1.'''</summary>'''<param name="str"></param>'''<param name="pos"></param>'''<param name="len"></param>'''<remarks>10/Sep/20/20</remarks>PublicSharedFunction Mid(str AsString, pos AsInteger, len AsInteger) AsStringReturn str.Substring(pos - 1, len)
EndFunction'''<summary>''' Devuelve el número de caracteres.''' Si es cadena vacía o nulo devuelve 0.'''</summary>'''<param name="str"></param>'''<returns></returns>PublicSharedFunction Len(str AsString) AsIntegerIfString.IsNullOrEmpty(str) ThenReturn 0
Return str.Length
EndFunction'''<summary>''' Devuelve los primeros caracteres de la cadena.'''</summary>'''<param name="str"></param>'''<param name="len"></param>'''<returns></returns>PublicSharedFunction Left(str AsString, len AsInteger) AsStringReturn str.Substring(0, If(len > str.Length, str.Length, len))
EndFunction'''<summary>''' Devuelve los caracteres indicados desde la derecha.'''</summary>'''<param name="str"></param>'''<param name="len"></param>'''<returns></returns>PublicSharedFunction Right(str AsString, len AsInteger) AsStringDim iPos = str.Length - len
Return str.Substring(iPos, len)
EndFunction'''<summary>''' Devuelve la posición (en base 1) de la segunda cadena en la primera'''</summary>'''<param name="str1"></param>'''<param name="str2"></param>'''<returns></returns>PublicSharedFunction InStr(str1 AsString, str2 AsString) AsIntegerReturn str1.IndexOf(str2) + 1
EndFunction'''<summary>''' Devuelve la posición (en base 1) de la segunda cadena en la primera ''' empezando en la posición indicada.'''</summary>'''<param name="startPos"></param>'''<param name="str1"></param>'''<param name="str2"></param>'''<returns></returns>PublicSharedFunction InStr(startPos AsInteger, str1 AsString, str2 AsString) AsIntegerReturn str1.IndexOf(str2, startPos - 1) + 1
EndFunction'''<summary>''' Devuelve una cadena después de haber quitado ''' los espacios delante y detrás.'''</summary>'''<param name="str"></param>'''<returns></returns>PublicSharedFunction Trim(str AsString) AsStringReturn str.Trim
EndFunction'''<summary>''' Divide una cadena en elementos de un array.''' Usando el delimitador indicado.'''</summary>'''<param name="Expression"></param>'''<param name="Delimiter"></param>'''<returns></returns>PublicSharedFunction Split(Expression AsString, Optional Delimiter AsString = " ") AsString()
Return Expression.Split(Delimiter.ToCharArray, StringSplitOptions.RemoveEmptyEntries)
EndFunction'''' El código IL de Prueba1 es más corto (y parece que eficiente) que el de Prueba2'''Public Shared Function Prueba1(str As String, len As Integer) As String' Return str.Substring(0, If(len > str.Length, str.Length, len))'End Function'Public Shared Function Prueba2(str As String, len As Integer) As String' If len > str.Length Then' len = str.Length' End If' Return str.Substring(0, len)'End FunctionEndClass
Y esto es todo por ahora…
Espero que te sea de utilidad
Nos vemos. Guillermo
El código fuente completo
El código para Visual Basic con el proyecto para Visual Studio 2019 está publicado en gitHub.
Pues eso… si eres de los que no entran habitualmente en el sitio del Guille (www.elguille.info) y prefieres ver las cosas publicadas aquí en el blog, te diré que ayer publiqué la nueva versión de la utilidad gsColorearCodigo. Y digo NUEVA porque la actualización anterior que publiqué fue hace ya unos 13 añitos de nada 😉 y era para .NET 2.0, mientras que la nueva es para .NET Framework 4.8.
Para facilitar la «coloración» del código a publicar en la WEB esta nueva versión permite copiar el código de Visual Studio, pegarlo en la ventana de la utilidad y generar el código HTML a partir del contenido RTF (ver la figura 1).
Figura 1. La utilidad gsColorearCodigo usando Colorear desde RTF
Esto tiene dos ventajas, la primera es que no es necesario que la utilidad analice el código fuente buscando palabras clave y comentarios, etc. Ya que lo único que tiene que hacer es convertir el código interno del formato RTF y convertirlo en etiquetas span.
Además que al hacerlo así se gana tiempo… te lo digo por experiencia, ya que prácticamente todo el código coloreado que publico desde hace 12 o 13 años lo hago usando esa opción… así que… ya sabes… 😉
Y para muestra, un código coloreado, precisamente el que usé para hacer la captura de la figura 1.
Te lo vuelvo a mostrar en la captura de la figura 2, que es el editor de Visual Studio 2019.
Figura 2. El código a copiar del editor de Visual Studio 2019
Y este es el código HTML generado :
'''<summary>
''' Devuelve la versión de la DLL.
''' Si completa es True, se devuelve también el nombre de la DLL:
''' gsColorear v 1.0.7.0 (para .NET Framework 4.7.2 revisión del dd/MMM/yyyy)
'''</summary>
PublicSharedFunction Version(Optional completa AsBoolean = False) AsString
Dim res = ""
Dim ensamblado = System.Reflection.Assembly.GetExecutingAssembly
'Dim m_fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(ensamblado.Location)
'res = $"v {m_fvi.FileVersion}"
Dim versionAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyVersionAttribute), False)
'DirectCast(DirectCast(versionAttr, System.Reflection.AssemblyVersionAttribute())(0), System.Reflection.AssemblyVersionAt
Dim vers = If(versionAttr.Length > 0, (TryCast(versionAttr(0), System.Reflection.AssemblyVersionAttribute)).Version,
"1.0.7.0")
Dim fileVerAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyFileVersionAttribute), False)
Dim versF = If(fileVerAttr.Length > 0, (TryCast(fileVerAttr(0), System.Reflection.AssemblyFileVersionAttribute)).Version,
"1.0.7.1")
res = $"v {vers} ({versF})"
If completa Then
Dim prodAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyProductAttribute), False)
Dim producto = If(prodAttr.Length > 0, (TryCast(prodAttr(0), System.Reflection.AssemblyProductAttribute)).Product,
"gsColorear")
res = $"{producto}{res} (para .NET Framework 4.7.2 revisión del 09/Sep/2020)"
EndIf
Return res
EndFunction
En este caso, el VS no ha pasado los colores de los tipos (verde azulado), pero en otras ocasiones sí que lo hacía y quedaba guay, pero últimamente no le pasa los datos del color al código que utiliza de RTF… en fin…
Nota adicional sobre el coloreado de Visual Studio
Comenté en el párrafo anterior que Visual Studio no pasa los colores de las clases (verde azulado) y antes lo hacía. ¿Lo habrán quitado?
No, no lo han quitado.
Y es que el que lo haga o no depende de una opción en la configuración del editor de textos de Visual Studio.
Esa opción en español es: Usar clasificación precisa. En inglés es: Use accurate classification.
Y con esos nombres… ¿Quién lo iba a saber?
Para poder cambiar (activar) esa opción lo tienes que hacer en: (ver la captura) Herramientas>Opciones>Editor de textos>Avanzadas En inglés sería: Tools>Options>Text editor>Advanced
Opción para que al copiar el código en Visual Studio coloree también las definiciones de los tipos
Fíjate que también tiene que estar seleccionada la opción Copiar texto enriquecido al copiar o cortar (Copy rich text on copy/cut).
Al pegar el texto coloreado, quedaría así:
'''<summary>
''' Devuelve la versión de la DLL.
''' Si completa es True, se devuelve también el nombre de la DLL:
''' gsColorear v 1.0.7.0 (para .NET Framework 4.7.2 revisión del dd/MMM/yyyy)
'''</summary>
PublicSharedFunction Version(Optional completa AsBoolean = False) AsString
Dim res = ""
Dim ensamblado = System.Reflection.Assembly.GetExecutingAssembly
'Dim m_fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(ensamblado.Location)
'res = $"v {m_fvi.FileVersion}"
Dim versionAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyVersionAttribute), False)
'DirectCast(DirectCast(versionAttr, System.Reflection.AssemblyVersionAttribute())(0), System.Reflection.AssemblyVersionAt
Dim vers = If(versionAttr.Length > 0, (TryCast(versionAttr(0), System.Reflection.AssemblyVersionAttribute)).Version,
"1.0.7.0")
Dim fileVerAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyFileVersionAttribute), False)
Dim versF = If(fileVerAttr.Length > 0, (TryCast(fileVerAttr(0), System.Reflection.AssemblyFileVersionAttribute)).Version,
"1.0.7.1")
res = $"v {vers} ({versF})"
If completa Then
Dim prodAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyProductAttribute), False)
Dim producto = If(prodAttr.Length > 0, (TryCast(prodAttr(0), System.Reflection.AssemblyProductAttribute)).Product,
"gsColorear")
res = $"{producto}{res} (para .NET Framework 4.7.2 revisión del 09/Sep/2020)"
EndIf
Return res
EndFunction
Lo que si hace es usar la coloración de las cadenas con los argumentos de las cadenas interpoladas (las que se usan poniendo un signo dólar delante del inicio de las comillas dobles) que utiliza la coloración de Visual Studio, mientras que si lo haces con el comando Colorear en HTML, todo el contenido de la cadena estaría de color rojo, tal como puedes ver a continuación.
res = $"{producto} {res} (para .NET Framework 4.7.2 revisión del 09/Sep/2020)"EndIfReturn res
EndFunction
Aunque con la utilidad puedes configurar los colores y usar Colorear en HTML y mostrar el código con el look ese que tanto le gusta a «los otros» 😉
''' <summary>''' Devuelve la versión de la DLL.''' Si completa es True, se devuelve también el nombre de la DLL:''' gsColorear v 1.0.7.0 (para .NET Framework 4.7.2 revisión del dd/MMM/yyyy)''' </summary>PublicSharedFunction Version(Optional completa AsBoolean = False) AsStringDim res = ""
Dim ensamblado = System.Reflection.Assembly.GetExecutingAssembly
'Dim m_fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(ensamblado.Location)'res = $"v {m_fvi.FileVersion}"Dim versionAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyVersionAttribute), False)
'DirectCast(DirectCast(versionAttr, System.Reflection.AssemblyVersionAttribute())(0), System.Reflection.AssemblyVersionAtDim vers = If(versionAttr.Length > 0, (TryCast(versionAttr(0), System.Reflection.AssemblyVersionAttribute)).Version,
"1.0.7.0")
Dim fileVerAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyFileVersionAttribute), False)
Dim versF = If(fileVerAttr.Length > 0, (TryCast(fileVerAttr(0), System.Reflection.AssemblyFileVersionAttribute)).Version,
"1.0.7.1")
res = $"v {vers} ({versF})"If completa ThenDim prodAttr = ensamblado.GetCustomAttributes(GetType(System.Reflection.AssemblyProductAttribute), False)
Dim producto = If(prodAttr.Length > 0, (TryCast(prodAttr(0), System.Reflection.AssemblyProductAttribute)).Product,
"gsColorear")
res = $"{producto} {res} (para .NET Framework 4.7.2 revisión del 09/Sep/2020)"EndIfReturn res
EndFunction
Por si te interesa, aquí tienes los colores a usar y el valor de «pre» para conseguir ese coloreado del código:
Tag del formato <pre>: <pre style=»background-color:black; color:#dcdcdc»> Color texto: d69d85 Color comentario: 57a64a Color documentación (XML): 57a64a Color instrucciones: 569cd6
Bueno, no te canso más… espero que te sea de utilidad y la uses si necesitas colorear código para publicar en una sitio web.
El código fuente y el instalador de ClickOnce lo encontrarás en la página que publiqué en elGuille.info.
P.S. Ahora que veo el código publicado… no queda mal el fondo negro con el resto de colores… lo mismo modifico la utilidad de colorear para que al colorear desde RTF utilice esos colores en vez de los «predeterminados», que yo creo que son los que recoge del código RTF de Visual Studio, pero lo mismo es fácil de cambiarlos. Si lo logro, ya te enterarás con una nueva actualización 😉