Compilar código Java desde la línea de comandos

Pues eso… probando con el código que he hecho con Java (desde el IntelliJ IDEA) he querido compilar el código a .exe, pero no sé cómo hacerlo… solo me he quedado en crear un fichero .jar y ese poder ejecutarlo con el «java» desde la línea de comandos.

Versión de Java instalado

Al intentar hacerlo me he topado con un par de problemas, al menos desde mi máquina con el Visual Studio 2019 instalado (aparte del Visual Studio 2022), aclaro esto porque se ve que el Visual Studio 2019 tiene instalada una versión del JDK más antigua, concretamente la versión 1.8.0_302 y el código que he usado en las pruebas con records y expresiones swicht necesita al menos el JDK 17 (JDK = Java Development Kit).

Para poder usar el código que he publicado en varios de los repositorios (y los gists) de GitHub, instalé el JDK 19 (el último a la hora de escribir esto y también cuando empecé a hacer las pruebas en noviembre), pero la versión del JDK que está primero en la variable PATH es la carpeta bin de la versión 1.8, por tanto, al usar cualquiera de los comandos de Java (java para ejecutar los .jar o javac para compilar el código) me daba error.

Cuando se instala el JDK (al menos desde Visual Studio) se crea una variable de entorno que se llama JAVA_HOME con el path del directorio donde está instalado el JDK de Java.
En mi equipo el path indicado es: C:\Program Files\Microsoft\jdk-11.0.12.7-hotspot. Que como te puedes imaginar es la versión 11 del JDK. Esa versión tampoco soporta las expresiones swicht ni los records (aunque sí los tipos genéricos).

Así que… la solución es instalar un JDK que soporte esas dos «cosillas» que necesito en mi código.

Instalar un nuevo JDK de Java

Como la última versión que hay actualmente es la 19, esa es la que descargué (desde el propio IDE de IntelliJ IDEA), pero que puedes descargar desde la página de OpenJDK.

A fecha de hoy (27 de noviembre) el último JDK de Java es el 19, pero también puedes descargar versiones anteriores, aunque… ¿para qué? si con el último te aseguras que lo tienes todo 😉
Quiero comentarte que desde esa página puedes descargar la versión del JDK para distintos sistemas operativos. En mi caso descargué el de Windows.

Si quieres usar otra versión anterior, por ejemplo, la implementación del Java SE 17 también valdría, puedes hacerlo desde los enlaces de la parte izquierda de la página del enlace que te he puesto en el párrafo anterior.

Para usarlo, te descargas el zip, lo extraes en una carpeta (normalmente en la carpeta .jdks del directorio de %USERPROFILE% (la carpeta predeterminada del usuario de Windows).

En mi caso, ahí tengo el JDK 19 (instalado por IntelliJ IDEA) y el JDK 17 que me lo descargué para comprobar que con esa versión también funciona.

Lo que hice a continuación es añadir variables de entorno para acceder fácilmente a esos directorios, concretamente he creado dos variables de entorno, una para el JDK 19 y otra para el JDK 17.

Para hacer esto, abre las opciones avanzadas del sistema (Advanced System Settings) y acceder a las variables de entorno (Environment Variables).
Para acceder, pulsa con el botón secundario en This PC > Settings y en el panel derecho (estoy usando Windows 11) pulsa en Advanced System Settings o bien en buscar escribe «Advanced System Settings» o desde la línea de comandos (o desde run) escribe control sysdm.cpl y selecciona la ficha «Advanced»

Una vez tengas las variables de entorno (ver la figura 1), pulsa en el botón New de la parte superior y en el cuadro de diálogo escribe JAVA_HOME19 y en el path escribe el directorio en el que está ese JDK, en mi caso escribí %USERPROFILE%\.jdks\openjdk-19.0.1 y después se puso el path que corresponde.

Figura 1. Las variables de entorno

No es necesario que pongas los dos paths a los dos JDK, yo solo los he puesto para comprobar que la versión 17 también servía.

Una vez que tengas esto, abre la terminal o la línea de comandos y escribe %JAVA_HOME19%\bin\java --version para comprobar la versión del JDK de Java instalado.

Microsoft Windows [Version 10.0.22000.1281]
(c) Microsoft Corporation. All rights reserved.

C:\Users\Guille>%JAVA_HOME19%\bin\java --version
openjdk 19.0.1 2022-10-18
OpenJDK Runtime Environment (build 19.0.1+10-21)
OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing)

Puedes escribir tanto java --version como java -version, el resultado prácticamente es el mismo, pero no igual; además de que -version se muestra en el stream de error y –version en el stream de salida.

Te aclaro que todo esto es por si el Java que tienes instalado es anterior a la versión 17, cosa que ocurrirá si tienes Visual Studio instalado y has indicado que quieres crear aplicaciones de Xamarin o .NET MAUI que instalan los JDK de Java.

En cualquier caso, antes de ahcer todo lo aquí explicado, comprueba con java -version (sin indicar ningún path y con un solo guión, ya que las versiones anteriores no reconocen el parámetro --version) qué versión tienes y si es la 17 o superior, pues… ¡todo hecho!

En mi caso me muestra esto, así que, necesito instalar un JDK más reciente.

Microsoft Windows [Version 10.0.22000.1281]
(c) Microsoft Corporation. All rights reserved.

C:\Users\Guille>java -version
openjdk version "1.8.0_302"
OpenJDK Runtime Environment (Temurin)(build 1.8.0_302-b08)
OpenJDK 64-Bit Server VM (Temurin)(build 25.302-b08, mixed mode)

Al compilar el código te explicaré para qué he creado la variable de entorno %JAVA_HOME19%, ya que no he querido añadir el path al directorio bin del JDK en la variable de entorno PATH para que no afecte a lo que Visual Studio necesita.

El código de prueba

Para esto que te comentaré en este post, voy a usar el código publicado en el gist Evaluar.java (gist = trozo de código publicado en GitHub).

En ese código, utilizo la expresión switch (no confundir con la sentencia switch) y los records con tipos genéricos para simular una tuple de 2 valores, (tuple = una estructura de datos que consiste en múltiples partes).

Nota:
En el lenguaje Java no existe el «tipo tuple» aunque hay implementaciones que, si lo tienen, como por ejemplo JavaTuples de Maven (en esta página puedes ver algunos ejemplos de JavaTuples), pero no en el JDK oficial (al menos a día de hoy).

Como en mi código necesitaba que una función devolviese dos valores, lo simulé con un record de tipo genérico. Este es el código:

/**                                                                             
 * Tuple de dos valores para usar al buscar un operador y la posición del mismo.
 *                                                                              
 * @param operador Un valor del tipo T1.                                        
 * @param position Un valor del tipo T2.                                        
 * @param <T1> El tipo (por referencia) del primer parámetro.                   
 * @param <T2> El tipo (por referencia) del segundo parámetro.                  
 */                                                                              
record TuplePair<T1, T2>(T1 operador, T2 position) {                            
}

Compilar el código JAVA y crear el fichero .jar

Descarga el fichero ese de prueba, en el que utilizo 3 clases (2 clases y un record) ambos definidos dentro de la clase Evaluar (fichero Evaluar.java) y cópialo en cualquier carpeta de tu equipo.

Todo lo que aquí te explico también serviría si la clase ConsoleColor está definida en un fichero independiente, aunque el record (TuplePair) debe estar definido dentro de la clase Evaluar, ya que se accede directamente a los campos privados del record en vez de a métodos públicos. Esos campos privados son accesibles desde la clase Evaluar porque el record está definido «dentro» de esa clase.

Compilar el código con javac

Para compilar el código usamos javac indicando los ficheros .java a compilar, opcionalmente le podemos indicar en qué directorio queremos que se creen los ficheros compilados (con extensión .class) y la codificación de esos ficheros, por ejemplo:

%JAVA_HOME19%\bin\javac -d .\ -encoding UTF-8 *.java

En este caso, los ficheros .java están en la misma carpeta desde la que se ejecuta javac.exe y le indicamos que la carpeta para los ficheros .class generados sean en la misma carpeta, (en realidad ese comando u opción -d lo podríamos haber obviado) y que el enconding de los ficheros es UTF-8.

Si el código de los ficheros .java está en otra carpeta, por ejemplo, la carpeta src dentro del directorio actual, y queremos que los ficheros .class se guarden en la carpeta actual, podríamos escribir:

%JAVA_HOME19%\bin\javac -d .\ -encoding UTF-8 .\src\*.java

Crear y usar el .jar ejecutable

Una vez generados los ficheros .class nos toca usar el comando jar.exe para crear un fichero .jar.

Por ejemplo:

%JAVA_HOME19%\bin\jar cf evaluar.jar *.class

Este comando crea el fichero .jar pero sin indicar dónde encontrar el método main.

Para probar el código compilado tendríamos que hacerlo de esta forma:

%JAVA_HOME19%\bin\java -cp evaluar.jar Evaluar 25+(2*3)+5!

Con esto le estamos indicando que utilice el fichero evaluar.jar, que el método main está en la clase Evaluar y por último los parámetros que queremos pasarle al programa.

Otra forma de usar el código compilado (sin necesidad de que el fichero .jar esté presente, aunque sí los ficheros .class) es:

%JAVA_HOME19%\bin\java Evaluar 25+(2*3)+5!

Aquí le indicamos que use el el método main de la clase Evaluar y pase los parámetros indicados como argumentos del programa.

Crear y usar el .jar con un manifiesto que indica dónde encontrar el método main

Pero lo mejor es crear un fichero de manifiesto donde se le indique al comando jar.exe dónde está (o cuál es) el método main que queremos usar.

Para ello creamos un fichero de texto con el siguiente contenido:

Main-Class: Evaluar

Después de Main-Class: indicaremos el nombre de la clase en la que está definido el método main. Recuerda que el nombre de la clase distingue entre mayúsculas y minúsculas.

Esto lo podemos crear directamente desde la línea de comandos escribiendo lo siguiente:

echo Main-Class: Evaluar > manifiesto.txt

Una vez que tenemos ese fichero del manifiesto, podemos crear el fichero .jar de esta forma:

%JAVA_HOME19%\bin\jar cvmf manifiesto.txt evaluar.jar *.class

Y para usarlo tendríamos que hacerlo de esta otra:

%JAVA_HOME19%\bin\java -jar evaluar.jar 25+(2*3)+5!

Si esto último lo hacemos con un .jar sin manifiesto obtendríamos el siguiente error:

no main manifest attribute, in evaluar.jar

Nota:
El nombre del fichero manifiesto puede ser el que quieras y con la extensión que quieras. Aunque el nombre recomendado es MANIFEST.MF.

De hecho, si abres un fichero .jar (que en realidad es como un fichero comprimido) puedes ver que la estructura en la que se incluye una carpeta llamada META-INF con el manifiesto, incluso si no indicamos un manifiesto esa carpeta y el correspondiente fichero MANIFEST.MF se crea, aunque sin indicar qué clase contiene el método main.

El contenido del MANIFEST.MF, del .jar que hemos generado, sería este si se ha indicado dónde está el método main):

Manifest-Version: 1.0
Main-Class: Evaluar
Created-By: 19.0.1 (Oracle Corporation)

Además de esa carpeta se incluyen todos los .class que se hayan generado (un .class por cada clase incluida en el código).

Y esto ha sido todo amigos… espero que te sirva…

Nos vemos.
Guillermo

Evaluar expresiones (código en Java y C#)

Pues eso… Sí, has leído bien el título: en Java. Y no en JavaScript (aparte de en C#).

Y es que hace unos días, empecé a estudiar esto de Java a raíz que mi hijo David está haciendo un curso de Java (back-end) y era por si le echaba una mano en algunos conceptos, ya que lo que él estudio en su día fue COBOL, algo de Pascal y algo de Visual Basic 6, y claro… los conceptos de POO y esas cosas, como que no las tiene claras.

Y para poder ayudarle (si es que así me lo hace saber), me puse a «trastear» en Java, y de camino he aprendido entre otras cosas, que hay diferencias, algunos grandes, en comparación con C# que es lo más parecido, (con Visual Basic ni te cuento).

Algunas de esas diferencias son a favor de Java, y la mayoría, a favor de C# o si lo prefieres a favor de .NET, seguramente porque lo conozco más.

Pero sea como sea, y peleándome un poco con el código y el IDE, que por cierto estoy usando uno que me parece muy bueno y es gratis: IntelliJ IDEA (Community Edition) de JetBrains, he conseguido hacer algo más o menos operativo y que me está enseñando algunas de esas cosas que ni siquiera sabía que C# las tenía y otras que al parecer C# tiene porque Java las tenía.

Lo que más he echado en falta son las «tuplas», aunque en este código de evaluar expresiones aritméticas he solventado con records, más que nada porque en algunas funciones necesitaba devolver dos valores (seguramente en Java habrá otra forma de hacerlo, pero no la he encontrado). Otra cosa que he echado en falta en Java es las estructuras (tipos de datos definibles, pero por valor).

 

No te voy a explicar «paso a paso» el código ni nada de eso (al menos por ahora), simplemente te voy a decir lo que este evaluador sabe hacer (creo que lo hace bien) y el código lo podrás ver en el repositorio de GitHub.

Quiero comentarte que primero hice una versión usando records para hacer las operaciones de suma, restas, multiplicación y división (basándome en un ejemplo de la documentación de Java), y el último es usando tipos double que además de esas cuatro operaciones hace un par de ellas más: módulo y factorial.

El enlace de GitHub o, mejor dicho, los enlaces son para el código basado en el tipo double, en esos repositorios tienes los enlaces al código fuente que usa los records, tanto para Java como para C#.

 

Lo que hace el evaluador de expresiones

  • Evalúa expresiones entre paréntesis (con varios niveles de anidación).
  • Evalúa primero los operadores multiplicativos (* y x para multiplicar, / y : para dividir y % para el módulo) y después los operadores aditivos (+ para sumar, – para restar).
  • La expresión puede tener espacios, pero al evaluarla se quitan, por tanto: «1 5 * 2» se convierte en «15*2».
  • Si hay un paréntesis de apertura precedido por un dígito o de un paréntesis de cierre, se considera una multiplicación y se pone el signo *.
  • Si hay un paréntesis de cierre seguido de un dígito o de un paréntesis de apertura, se considera una multiplicación y se pone el signo *.
  • Evalúa factoriales (usando el carácter «!»), tanto de números enteros positivos (naturales) como números negativos con parte decimal.
  • El valor de la factorial para números no naturales se calcula usando la función gamma basada en un código adaptado de un ejemplo de StackOverflow.

 

El código de Java y C# en GitHub

Estos son los enlaces del código fuente que tengo publicado en GitHub:

EvaluarExpresiones-java y EvaluarExpresiones-csharp.

Espero que te sea de utilidad.

Nos vemos.
Guillermo

Edad de elGuille.info es 2022 – 1996 = 26

Pues eso… 26 añitos de nada que el menda ese llamado «Guille» empezó su andadura por estas tierras sin tierra… o por esta maraña enredada… 😉

Lo de «edad de elguille.info» es porque, aunque ese nombre solo empezó a finales de 2005 (de noviembre de 1996 a finales de 2005 hubo otros nombres varios, desde carpetas en wcostasol.es hasta subdominios de costasol.net), y ahora el que «mola» es este blog, pero en el fondo todo es «el Guille punto info«.

Y espero seguir contando… jejeje

Nos vemos.
Guillermo

gsNotas para .NET

Pues eso… para que exista como entrada en el blog, ya que inicialmente lo he publicado como una página.

El código fuente está en este repositorio de GitHub y ahí iré indicando los cambios y novedades de la aplicación.

Está escrita enteramente en C#.

Espero que te sea de utilidad.

Nos vemos.
Guillermo

Errores de iOS con .NET MAUI

Pues eso… todo iba bien con las aplicaciones de .NET MAUI para iOS (después de muchos quebraderos de cabeza) y ahora, de buenas a primeras, empezó a pasar después de actualizar Visual Studio 2022 de la versión 17.3.5 a la 17.3.6.

Nota del 16-oct-22:

Solución a medias (que al menos me sirve para seguir probando las aplicaciones de .NET MAUI en iOS).

He usado el proyecto en otro equipo (un laptop/portátil) con Visual Studio 2022 Preview y ahí sí que ha funcionado todo.
Así de simple.
No es mi equipo habitual, y las copias que tengo no incluyen los ficheros de github, pero al menos me ha permitido seguir probando cosas.

Un consuelo como otro cualquiera. 😉

El error que me ha dado es este:

Error: CS1705 Assembly ‘Microsoft.Maui’ with identity ‘Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ uses ‘Microsoft.iOS, Version=16.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065’ which has a higher version than referenced assembly ‘Microsoft.iOS’ with identity ‘Microsoft.iOS, Version=15.4.300.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065’

He reportado el error, ya que lo que encontré no me solucionaba el problema.

Lo último que hice fue desinstalar totalmente el Visual Studio 2022 y después volver a instalarlo, antes hice un Rollback a la versión anterior, y probé con prácticamente todas las opciones de dotnet workload, pero sin ningún resultado favorable.

En el bug que reporté me decían que estaba duplicado y ahí he leído que aparte de desinstalar el Visual Studio, hay que desinstalar el SDK de .NET 6, esto último no lo he hecho pensando que se instalaba con el propio Visual Studio, lo mismo que el SDK de .NET 7 se instala con el Visual Studio 2022 Preview (que ya antes lo tuve que desinstalar para que las apps de .NET MAUI funcionaran sin darme error de que faltaban workloads.

Bueno, pues voy a ver si puedo desinstalar el .NET SDK aunque tenga que volver a instalar el Visual Studio al completo… 🙄

Ya te iré contando. 🤞🏻🙏🏻🤔

Pasos seguidos

Paso 1: Desinstalar el .NET SDK 6.0.305

Figura 1. Desinstalar el .NET SDK 6.0.305

Paso 2: Desinstalar el .NET SDK 6.0.402

Figura 2. Al desinstalar el .NET SDK 6.0.305 dice que nones

Como ves en la figura 2, al querer desinstalar el .NET SDK 6.0.402 me dice que no, que lo ha instalado el Visual Studio.

Después del paso 2, la cosa sigue igual.

Paso 3: Desinstalo los SDK de MAUI y .NET 6 desde el instalador de Visual Studio

Figura 3. Desinstalo desde el instalador de VS los SDK de MAUI y los de Android, iOS y normal

Ahora se supone que no podré crear nada… salvo la app de Windows.
A ver qué pasa…🤞🏻

Estos son los errores que me da el Visual Studio al no tener los SDK (figura 4), ni la app de Windows funciona (normal, no hay ningún SDK válido).

Figura 4. Los errores de Visual Studio al no tener los SDK.

Ahora probaré a volver a instalarlos. Aunque antes voy a reiniciar el equipo.

Paso 4: Después de reiniciar el equipo, quito todo del instalador de Visual Studio

Y ahora iré añadiendo los workloads y demás…

Figura 5. Quito todo y ahora a indicar lo que se debe instalar

Paso 5: Selecciono los Workloads en el instalador de Visual Studio

Figura 6. Selecciono los Workloads en el instalador de Visual Studio

Y compruebo que los SDK estén (figura 7)

Figura 7. Los componentes individuales al configurar los workloads

A ver qué pasa después de instalar… 🤞🏻🤔

Conclusión de estos 6 pasos

¡No hay que rascar! todo sigue igual de mal (con la app para iOS).
Las aplicaciones de Windows y Android van bien.

Ahora me toca quitar el SDK de iOS a ver qué pasa… Ya no sé si cruzar los dedos o levantar uno… 🤔🙄☝🏻 (pero no el central que no es plan, jajaja)

Paso 7: Quito el SDK de iOS

Con esto tampoco funcionará, pero a ver si lo puedo instalar usando dotnet workload.

Figura 8. Quito el SDK de iOS

Esto es lo que muestra dotnet --info antes de hacer nada.

E:\gsCodigo_00\Visual Studio\pruebas\MAUI\Trucos_MAUI>dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.402
 Commit:    6862418796

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22000
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.402\

global.json file:
  E:\gsCodigo_00\Visual Studio\pruebas\MAUI\Trucos_MAUI\global.json

Host:
  Version:      6.0.10
  Architecture: x64
  Commit:       5a400c212a

.NET SDKs installed:
  3.1.424 [C:\Program Files\dotnet\sdk]
  5.0.303 [C:\Program Files\dotnet\sdk]
  5.0.406 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  5.0.413 [C:\Program Files\dotnet\sdk]
  6.0.402 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.28 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.30 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Download .NET:
  https://aka.ms/dotnet-download

Learn about .NET Runtimes and SDKs:
  https://aka.ms/dotnet/runtimes-sdk-info

Paso 8: Usar dotnet workload restore con uno de los proyectos

Empezaré con el comando dotnet workload restore Trucos_MAUI.sln.
(Por eso estaba posicionado en el directorio con el proyecto de pruebas).

Y dice que:

E:\gsCodigo_00\Visual Studio\pruebas\MAUI\Trucos_MAUI>dotnet workload restore Trucos_MAUI.sln
Installing workloads:

Successfully installed workload(s) maui maui-android maui-ios maui-tizen.

A probar toca…

Ahora en el proyecto no me muestra las opciones de probar ni con iOS ni con Android y el que tiene una advertencia en las dependencias es el net6.0-android. En fin… 🙄

Paso 9: Instalo nuevamente los workloads (y SDKs) para MAUI (que se había desmarcado)

Paso 10: Instalo nuevamente el .NET 6.0 SDK (v6.0.305)

Figura 9. Instalo nuevamente el .NET SDK 6.0.305

Aunque antes voy a probar usando el que tenía antes (con el .NET 6.0.402) por si el instalador de Visual Studio lo ha dejado bien (cosa que dudo, pero… ¡hay que tener fe! 🙏🏻)

Sigue con la misma cantinela.

Paso 11: Cambio en global.json la versión de .NET SDK a la 6.0.305 en vez de la 6.0.402

Intentaré ponerlo para que lo use la solución (del proyecto) con el fichero global.json y este contenido:

{
  "sdk": {
    "version": "6.0.305"
  }
}

A ver qué pasa.

Lo suponía, ese SDK se incluía con el Visual Studio 17.2.9 y no incluye el .NET MAUI (que se incluyó con el Visual Studio 2022 17.3 😒

Por tanto, no se puede hacer nada ni con Windows siquiera… ¡Los milagros en Visual Studio no existen! 🤣

Paso 12: Vuelvo a poner en el global.json el .NET SDK 6.0.402

Y cuando abro el Visual Studio me sale esto:

Figura 10: Encima con cachondeo

Que tome una «survey» de mi experiencia con el desarrollo para iOS… si es que… 🙄

¡Hecho! Aunque, no hay mucho que decir… están más enfocados al emparejamiento con un Mac, que es lo que te permite distribuir las apps de iOS sin necesidad de tener el móvil junto a tu «computadora» para instalar la app.

Pero tampoco funciona… sigue con el mismo error.

Seguimos…

Paso 13: Vuelvo a probar con dotnet workload restore Trucos_MAUI.sln.

Pero nada… sigue igual.

Paso 14: En vista que el .NET SDK 6.0.305 no me vale, lo vuelvo a desinstalar

Y después de desinstalar este SDK que ya no me vale, no sé qué más hacer… 🤷🏻‍♂️

Nota del 13-oct-22 00.08:
Como consuelo me ha quedado que al menos las apps de Xamarin para iOS funcionan desde Visual Studio 2022, ya que en Visual Studio 2019 no pueden firmar la app… cosas que pasan…
Ver esto: Truco 3 de .NET MAUI.

Nos vemos.
Guillermo

Trucos para .NET MAUI (segunda parte)

Pues eso… seguimos con los trucos para .NET MAUI, en la primera parte te mostré cómo configurar el proyecto para usar las plataformas que prefieras y cómo configurar el aprovisionamiento para iOS (necesitas una cuenta de Apple Developer). Ahora vamos a ver algunas cosillas referentes al diseño de la aplicación.

Para poder mostrarte estos trucos, he creado una aplicación para .NET MAUI con Visual Studio 2022 (community), pero no la versión Preview, ya que a la hora de escribir esto, la tengo desinstalada y así uso el .NET 6.0 (que es el que por ahora me está dando menos problemas, al menos teniendo el .NET 6 y el .NET 7 RC1).
La versión de Visual Studio 2022 es:
Microsoft Visual Studio Community 2022 (64-bit) Version 17.3.5

Acabo de instalar la versión 17.3.6 y sigue funcionando bien 😉

Truco 4: Mostrar bien los Frame sin que se corten

Cuando añades un Frame se suelen cortar los bordes (ver la figura 1)

Figura 1. Los frame se cortan las líneas

El código XAML para mostrar esto es el siguiente:

<ScrollView>
    <VerticalStackLayout
        Padding="10,0"
        VerticalOptions="Center">

        <Frame>
            <VerticalStackLayout Spacing="25">
                    <Image
                            Source="dotnet_bot.png"
                            SemanticProperties.Description="Cute dot net bot waving hi to you!"
                            HeightRequest="200"
                            HorizontalOptions="Center" />

                    <Label
                            Text="Hello, World!"
                            SemanticProperties.HeadingLevel="Level1"
                            FontSize="32"
                            HorizontalOptions="Center" />

                    <Label
                            Text="Welcome to .NET Multi-platform App UI"
                            SemanticProperties.HeadingLevel="Level2"
                            SemanticProperties.Description="Welcome to dot net Multi platform App U I"
                            FontSize="18"
                            HorizontalOptions="Center" />

                    <Button
                            x:Name="CounterBtn"
                            Text="Click me"
                            SemanticProperties.Hint="Counts the number of times you click"
                            Clicked="OnCounterClicked"
                            HorizontalOptions="Center" />

            </VerticalStackLayout>
        </Frame>
    </VerticalStackLayout>
</ScrollView>

Lo deseable es que esté como en la figura 2.

Figura 2. Los Frame deben mostrar todos los bordes

El truco consiste en añadir un margen al StackLayout que esté contenido en el Frame.

<Frame>
    <VerticalStackLayout Spacing="25" Margin="4">

¿Fácil verdad?

Nota:
Este fallo solo ocurre en las aplicaciones de Windows (WinUI)

Tal como te acabo de decir, este fallo (de que se corten las líneas del Frame) solo ocurre en las aplicaciones para Windows (WinUI), al menos en iOS y Android no pasa, tal como puedes ver en las capturas 3 y 4.

Figura 3. La app de prueba en un iPhone 7 plus (iOS)
Figura 4. La app funcionando en un Pixel 4a (Android)

En realidad, al menos en iOS y Android, da igual que esté lo de Margin = «4» como que no, el efecto es prácticamente el mismo.

Truco 5: Cambiar el tamaño de la ventana en Windows

Otro de los problemas (al menos con la compilación actual de .NET MAUI) es que la ventana de la aplicación de Windows (WinUI) se muestra prácticamente a pantalla completa, y, ya te digo que al menos por ahora, ese tamaño no es configurable de forma automática o, que ocurra como en las aplicaciones para Xamarin en la que el usuario es el que decide qué tamaño y posición debe tener la ventana, de forma que en las próximas veces que se abra la aplicación se muestre como se dejó la última vez.

Nota:
En esta «issue de MAUI» dicen que se podrá hacer: Desktop: set window size and position #771 (pero ni idea de cómo o cuando estará disponible).

Lo que yo hago en estos casos es usar un tamaño «fijo» (que no es lo suyo, pero…) y asignarlo de esta forma en el constructor de la clase App.

public App()
    {
         InitializeComponent();

        // Indicar el tamaño para la app de Windows.
        Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
        {
#if WINDOWS

                // Asignar manualmente el tamaño. 
                int winWidth = 1000;
                int winHeight = 900;

                var mauiWindow = handler.VirtualView;
                var nativeWindow = handler.PlatformView;
                nativeWindow.Activate();
                IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
                var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
                var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
                appWindow.Resize(new Windows.Graphics.SizeInt32(winWidth, winHeight));

#endif
        });

        MainPage = new AppShell();
    }

Truco 6: Mostrar el título en la barra de la ventana (con colores personalizados)

Otra cosa que estoy haciendo desde hoy (al probar en la aplicación gsCrearTablas_MAUI) es posicionando la ventana y de paso cambiando el color a la barra de título (para que no se vea el color ese tan feo) y también mostrando el título en esa barra de la ventana.

Como puedes ver en la figura 2, no se muestra de color «normal» la barra de título y tampoco tiene un texto.

En la captura 5 puedes ver el color y el texto en la barra de título que podrás conseguir con el código que te muestro a continuación (después de la captura).

Figura 5. La app de Windows con texto y color en la barra de título

La asignación del color y texto de la ventana lo conseguimos haciendo esta asignación (en el código mostrado antes) lo tendrías que poner al final, después de appWindow.Resize.

// El título hay que asignarlo antes de asignar los colores.
appWindow.Title = "Trucos MAUI by elGuille";
// Este es el color que tiene en mi equipo la barra de título.
appWindow.TitleBar.BackgroundColor = Microsoft.UI.ColorHelper.FromArgb(255, 0, 120, 212);
appWindow.TitleBar.ForegroundColor = Microsoft.UI.Colors.White;

Para poder posicionarla, hace falta un truquillo más que es que la ventana se haya mostrado, ya que, si queremos acceder al tamaño de la pantalla, nos dará un valor nulo (o cero).

Nota:
El color que asigno a la propiedad BackgroundColor lo he sacado de cómo se muestra el color en mi equipo, por tanto, en tu caso, lo mismo lo tienes que cambiar: FromArgb(255, 0, 120, 212).

Truco 7: Esperar a que la ventana está mostrada para manipular la posición

Esto lo pones también en el primer código que te mostré en el truco 5, después de appWindow.Resize. Fíjate que el cambio del color y el título hay que hacerlo dentro del Dispatcher.Dispatch, si no, el título no se muestra.

// get screen size
DisplayInfo disp = DeviceDisplay.Current.MainDisplayInfo;
double x, y;

// dispatcher is used to give the window time to actually resize
Dispatcher.Dispatch(() =>
{
    disp = DeviceDisplay.Current.MainDisplayInfo;
    x = (disp.Width / disp.Density - winWidth) / 2;
    if (x < 0) 
    {
        x = 0;
    }
    y = (disp.Height / disp.Density - winHeight) / 2;
    if (y < 0)
    {
        y = 0;
    }
    appWindow.Move(new Windows.Graphics.PointInt32((int)x, (int)y));

    // Si cambiamos la posición, esto hay que hacerlo en el Dispatcher.Dispatch
    // El título hay que asignarlo antes de asignar los colores.
    appWindow.Title = "Trucos MAUI by elGuille";
    // Este es el color que tiene en mi equipo la barra de título.
    appWindow.TitleBar.BackgroundColor = Microsoft.UI.ColorHelper.FromArgb(255, 0, 120, 212);
    appWindow.TitleBar.ForegroundColor = Microsoft.UI.Colors.White;

Y con esto lo dejo por hoy… voy a seguir investigando (y probando) para poder ponerte algunos trucos más.

El código coloreado usando el condicional de WINDOWS (#if WINDOWS)

Pues eso, que habitualmente se muestra con el color grisáceo ese que te he mostrado antes cuando usas el condicional de compilación para Windows (#if WINDOWS) y, algunas veces, no sé cómo, sale coloreado (que es como debería salir).

Este código es de otra aplicación pero intentaré usar los mismos valores que en este proyecto de pruebas.

            // Indicar el tamaño para la app de Windows.
            Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
            {
#if WINDOWS

                // Asignar manualmente el tamaño. 
                int winWidth = 800; // 1700; // 2800;
                int winHeight = 640; //1800

                var mauiWindow = handler.VirtualView;
                var nativeWindow = handler.PlatformView;
                nativeWindow.Activate();
                IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
                var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
                var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
                //appWindow.Resize(new Windows.Graphics.SizeInt32(winWidth, winHeight));

                // get screen size
                DisplayInfo disp = DeviceDisplay.Current.MainDisplayInfo;
                double x, y;

                // dispatcher is used to give the window time to actually resize
                Dispatcher.Dispatch(() =>
                {
                    disp = DeviceDisplay.Current.MainDisplayInfo;
                    
                    // Si Density es diferente de 1, ajustar el tamaño.
                    if (disp.Density > 1)
                    {
                        winWidth = (int)(winWidth * disp.Density);
                        winHeight = (int)(winHeight * disp.Density);
                    }
                    // El tamaño de la pantalla de este equipo.
                    int screenW = (int)(disp.Width / disp.Density);
                    int screenH = (int)(disp.Height / disp.Density);
                    // Si el alto indicado es mayor, ponerlo para que entre en esta pantalla.
                    if (winHeight > screenH)
                    {
                        winHeight = screenH - 60;
                    }
                    // Si el ancho indicado es mayor, ponerlo para que entre en esta pantalla.
                    if (winWidth > screenW)
                    {
                        winWidth = screenW - 60;
                    }
                    appWindow.Resize(new Windows.Graphics.SizeInt32(winWidth, winHeight));
                    x = (screenW - winWidth) / 2;
                    if (x < 0) 
                    {
                        x = 0;
                    }
                    y = (screenH - winHeight - 40) / 2;
                    if (y < 0)
                    {
                        y = 0;
                    }
                    appWindow.Move(new Windows.Graphics.PointInt32((int)x, (int)y));

                    // El título hay que asignarlo antes de asignar los colores.
                    appWindow.Title = "Trucos MAUI by elGuille";
                    // Este es el color que tiene en mi equipo la barra de título.
                    appWindow.TitleBar.BackgroundColor = Microsoft.UI.ColorHelper.FromArgb(255, 0, 120, 212);
                    appWindow.TitleBar.ForegroundColor = Microsoft.UI.Colors.White;
                });

#endif
            });

Y, ya sabes, si te parece bien, puedes hacer un donativo con PayPal, que es como si me invitaras a un refresco, es decir, no es necesario que me dejes toda tu herencia, solo un par de euritos de nada… 😉

Nos vemos.
Guillermo

P.S.
El repositorio de GitHub ya está creado: Trucos_MAUI.

P.S.2
Por cierto, ahora no me funciona la app para iOS.
El error que da es:

Error CS1705: Assembly ‘Microsoft.Maui’ with identity ‘Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ uses ‘Microsoft.iOS, Version=16.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065’ which has a higher version than referenced assembly ‘Microsoft.iOS’ with identity ‘Microsoft.iOS, Version=15.4.300.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065’

He buscado (con BING, ya que con Google no encontraba nada al poner esa cadena) para ver de qué va esto y lo que he encontrado (https://github.com/dotnet/maui/issues/8858) dice que ya está resuelto (o algo así) y en teoría la solución que da a mí no me funciona, que si no he entendido mal es dotnet workload install (supongo que indicando o maui o ios) pero nada, también he probado con dotnet workload install ios, con dotnet workload update, con dotnet workload repair y posicionándome en el directorio del proyecto con dotnet workload restore Trucos_MAUI.csproj, pero nada de nada… Ni siquiera usando el peasso de comando este:
dotnet workload install maui --from-rollback-file https://aka.ms/dotnet/maui/6.0.408.json --source https://aka.ms/dotnet6/nuget/index.json --source https://api.nuget.org/v3/index.json
Pero nada de nada… ya, por último, hasta he desinstalado el Visual Studio (en realidad he usado la opción Rollback to previous version) la versión 17.3.6 (a la 17.3.5) pero tampoco ha solucionado nada de nada, así que… he vuelto a instalar la versión 17.3.6, que es la última a día de hoy.
A ver si para la siguiente tanda de trucos tengo la solución. 🤞🏻🙏🏻

P.S.3 (12-oct-22 17.35)
He creado otra entrada (Errores de iOS con .NET MAUI) con el problema este que te comento en el «P.S.2» con idea de ver si lo soluciono.

Trucos para .NET MAUI (primera parte)

Pues eso… aquí te muestro algunos trucos para usar con .NET MAUI para que no pierdas la razón como me está pasando a mí 😉

Para poder mostrarte estos trucos, he creado una aplicación para .NET MAUI con Visual Studio 2022 (community), pero no la versión Preview, ya que a la hora de escribir esto, la tengo desinstalada y así uso el .NET 6.0 (que es el que por ahora me está dando menos problemas, al menos teniendo el .NET 6 y el .NET 7 RC1).
La versión de Visual Studio 2022 es:
Microsoft Visual Studio Community 2022 (64-bit) Version 17.3.5

Acabo de instalar la versión 17.3.6 y sigue funcionando bien 😉

Truco 1: Crear la aplicación de pruebas y hacer que funcione

Lo primero es quitar las advertencias en los paquetes de NuGet (ver figura 1).

Figura 1. Advertencias en las dependencias del proyecto

Esto se soluciona ejecutando la aplicación (en mi caso para Windows).

Truco 2: Quitar los tipos de aplicaciones que no quieras usar

Aunque de paso he quitado el soporte para maccatalyst (ya que no tengo un Mac para poder probarlo). Esto es fácil de hacer, abres el fichero del proyecto (botón secundario sobre el nombre del proyecto, en mi caso Trucos_MAUI) y selecciona Edit Project File (en español será con otro texto: Editar el archivo de proyecto o algo así).

En la parte superior, busca esta línea: <net6.0-android;net6.0-ios;net6.0-maccatalyst> y cámbiala por esta otra: <net6.0-android;net6.0-ios>.

Truco 3: Usar la aplicación para iOS (iPhone, etc.)

Para poder usar la aplicación en iOS debes tener una cuenta en Apple Developer (99€ al año) y configurarlo para que use la versión «individual», es decir, con la definición normal de la cuenta no me funciona, y hay que asignar los valores de forma manual (yo ya los tengo asignados, pero voy a ver si te explico cómo hacerlo).

En las propiedades del proyecto (botón secundario en el proyecto y Properties del menú desplegable), selecciona en la parte de la izquierda iOS > Bundle Signing y en Scheme selecciona Automatic Provisioning (ver figura 2)

Figura 2. Configurar Bundle Signing para iOS

Pulsa en el «enlace» Configure Automatic Provisioning y te mostrará un asistente en el que tendrás que indicar la cuenta de Apple (puede ser que la tengas que indicar antes) y de ahí seleccionar la que hayas definido como cuenta de individual (no la que tiene el ID de Apple, si no la que configures manualmente, (ahora te explico cómo) (ver figura 3)

Figura 3. Las cuentas para configurar el aprovisionamiento para iOS

Para configurar la cuenta, pulsa en el enlace Manage Account (figura 2) y ahí tendrás que añadir tu ID de Apple (normalmente una cuenta de correo electrónico).

En el botón «Add» selecciona «Indivudual Account» (figura 4) y rellena los datos que te pide (en Apple Developer puedes encontrar esos datos y cómo crear el «private key». (figura 5).

Figura 4. añadir una cuenta individual
Figura 5. Configurar la cuenta individual

Nota:
Si necesitas saber cómo configurar la cuenta individual (figura 5), puedo ayudarte por un módico precio, vamos como una invitación virtual, pero me lo tienen que pedir y ya nos arreglamos con el donativo por PayPal 😉

Una vez que tienes todo esto, ya solo es compilar y cantar… 😉

Después sigo explicándote más cosas (pero lo primero era crear el proyecto de pruebas).

Este proyecto lo publicaré ya está publicado en GitHub para que puedas descargarlo e ir viendo el código y el diseño (ver abajo el enlace).

Nos vemos.
Guillermo

P.S.
El repositorio de GitHub ya está creado: Trucos_MAUI.

Cómo solucionar el error de .NET MAUI: Platform version is not present for one or more target frameworks

Pues eso, que al crear un proyecto para .NET MAUI con Visual Studio 2022 (no preview), concretamente con Microsoft Visual Studio Community 2022 (64-bit) – Version 17.3.5, al intentar usar el proyecto (incluso sin modificar nada) me soltaba ese error: Platform version is not present for one or more target frameworks (concretamente para ios).

Buscando en la red de redes (internet) me topé con varias soluciones que no solucionaban nada (o yo no sabía cómo aplicar esas soluciones, todo hay que decirlo), y al final «trasteando» con el comando workload de dotnet (que en su día usé, sin éxito, para intentar instalar el workload de iOS), probé con una de las opciones o comandos que te da. Al usar dotnet workload -h te muestra esto:

Commands:
  install <WORKLOAD_ID>         Install one or more workloads.
  update                        Update all installed workloads.
  list                          List workloads available.
  search <SEARCH_STRING>        Search for available workloads.
  uninstall <WORKLOAD_ID>       Uninstall one or more workloads.
  repair                        Repair workload installations.
  restore <PROJECT | SOLUTION>  Restore workloads required for a project.

Y de ahí la que he usado es la última, que suena bien…

Así que, te sitúas en el directorio en el que está el proyecto de .NET MAUI, y escribes (todo esto en la terminal, el shell o línea de comandos, como prefieras llamarlo):

dotnet workload restore "nombre del proyecto.csproj"

Por supuesto, debes sustituir «nombre del proyecto.csproj» por el nombre de tu proyecto y no es necesario ponerlo entre comillas.

Nota:
Puede ser que a los workloads se le vaya la olla… sí… así que… lo mismo un dotnet workload repair puede que lo tengas que usar.

Espero que a ti también te funcione.

Nos vemos.
Guillermo

Generar las clases (de VB o C#) de una tabla de SQL Server o Access (mdb)

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 As Exception
        msg = $"ERROR: {ex.Message}"
        ' Si hay error, deshacemos lo que se haya hecho.
        Try
            If tran IsNot Nothing Then
                tran.Rollback()
            End If
        Catch ex2 As Exception
            msg = $" (ERROR RollBack: {ex.Message})"
        End Try

    Finally
        con.Close()
    End Try

End Using

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).

Lo publicado originalmente en elGuilel.info

Los enlaces originales en www.elguille.info son estos:
– La página principal de la utilidad: Generar clases para acceder a una tabla.
– La página con el código y esas cosas: Utilidad para generar clases para acceder a una tabla.
– La página de actualización de cómo conseguir el código fuente: Esta me da error y estaba en CodePlex, ahora está en GitHub.

El final (del post)

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.

Nota:
Ya está publicado: gsCrearClaseTabla_20221001_1523.

Y ya sabes, si quieres ver el código fuente, está en el proyecto de GitHub (CrearClaseTabla).

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).

Cambiar el tamaño de la ventana de Windows (WinUI) en app de .NET MAUI

Pues eso… ahora le toca lo de cambiar el tamaño de una ventana de Windows (WinUI que es como se llama la plataforma de Windows en .NET MAUI (en Xamarin es UWP), aquí solo te voy a mostrar el código de un tamaño fijo, ya que no me he puesto a experimentar cómo usar el tamaño predeterminado, ya que la forma de hacerlo es con otras APIs y… pues eso… que no me gusta demasiado el .NET MAUI como para dedicarle más tiempo de lo justo y necesario… 😉

Lo que si te quiero decir, es que precisamente me puse a mirar todo esto de cambiar el tamaño porque a diferencia de las aplicaciones con Xamarin.Forms, als de .NET MAUI «no recuerdan» el tamaño de la ventana en las siguientes veces que se use la aplicación, algo que en las de Xamarin sí hace, es decir, se muestra con el tamaño predeterminado y si cambias el tamaño de la ventana, la próxima vez que se utilice usará ese último tamaño.

Pero en las aplicaciones de .NET MAUI, siempre usa el tamaño «grande» y… pues como que no, por eso me puse a investigar, primero para hacerlo en .NET MAUI, y ya puestos me puse a mirar para Xamarin.

¿Cómo cambiar el tamaño de la ventana de Windows (WinUI) en un proyecto de .NET MAUI?

Es muy simple, el código se pone en el constructor de la clase App principal (no la del proyecto de Windows) y el código podría ser como este que te muestro para poner la ventana en un tamaño de 800 x 900 (ancho x alto).

namespace CambiarTamañoWindows_MAUI;

public partial class App : Application
{
    public App()
    {
         InitializeComponent();


        // Indicar el tamaño para la app de Windows.
        Microsoft.Maui.Handlers.WindowHandler.Mapper.AppendToMapping(nameof(IWindow), (handler, view) =>
        {
#if WINDOWS
            // Asignar manualmente el tamaño. 
            int winWidth = 800;
            int winHeight = 900;

                        var mauiWindow = handler.VirtualView;
                        var nativeWindow = handler.PlatformView;
                        nativeWindow.Activate();
                        IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow);
                        var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(windowHandle);
                        var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
                        appWindow.Resize(new Windows.Graphics.SizeInt32(winWidth, winHeight));
#endif
        });

        MainPage = new AppShell();
    }
}

Y esto es todo lo que hay que hacer… simple, ¿verdad? pues sí, para qué engañarnos, aunque eso de tener que ponerlo en un condicional de compilación es un rollo, pero tiene sentido ya que solo es para un proyecto de Windows. El problema es que no te muestra nada el «intellisense» ni nada de esas monerías que tenía en el proyecto para Xamarin.

Una captura con el programa en funcionamiento.

Figura 1. La aplicación en funcionamiento.

Y esto es todo… ahora subiré el código (o parte de él) a GitHub y después te pondré el enlace.

Acuérdate de (si quieres) hacer un donativo en PayPal para poder seguir teniendo este sitio en funcionamiento, gracias.

Nos vemos.
Guillermo

P.S.
El código de ejemplo en GitHub: Cambiar Tamaño de la ventana de Windows (WinUI) con .NET MAUI.