Etiqueta: truco

  • Usar una class library desde proyecto de .NET MAUI

    Pues eso… algo tan simple como usar en .NET MAUI una DLL creada a partir de un proyecto del tipo class library, puede ser toda una odisea. Te lo explico para que te quede claro.

    Como ya sabrás, puedes crear proyectos del tipo class library para añadirlos como referencia a otros proyectos que usen esa DLL o biblioteca de clases. Algo que es bastante común en cualquier aplicación para .NET ya sea .NET Framework como para .NET a secas incluido los proyectos para aplicaciones móviles con Xamarin.Forms.
    En estes último, lo que se suele hacer es usar una DLL compilada para .NET Standard.
    Hasta aquí todo bien.

    La idea de usar una biblioteca de clases es para reutilizar el código en proyectos diferentes, es decir, creas la biblioteca de clases con cierta funcionalidad y esa misma biblioteca de clases la utilizas en proyectos diferentes. Al menos si esos tipos de proyectos son compatibles en el sentido de usar el mismo .NET.

    Y como ahora estoy haciendo pruebas de Google Cloud Natural Language, pues pensé crear algún proyecto para .NET MAUI que usara esa API. Y como ya tenía el código de ciertas clases creado como proyecto DLL (Class Library) pensé agregar la referencia al proyecto de .NET MAUI y… ¡yaumate! (una expresión de mi zona que quiere decir algo así como… ¡tararí que te vi! o… ¡que te lo has creído!)

    ¡Y así fue! ¡Me lo creí! Pensaba que en .NET MAUI las cosas seguirían siendo como en el resto de .NET, pero no…

    De hecho, hasta creé una class library usando la plantilla de MAUI, pero ni por esas… el proyecto de .NET MAUI nada más que daba errores de que no se podía tener referencia a esas clases definidas en la DLL (o class library).

    La solución que tomé fue añadir directamente el código de esas clases en el mismo proyecto de .NET MAUI y así funcionó, pero no era eso lo que yo pretendía, ya que además del proyecto para .NET MAUI tenía otros proyectos: de tipo consola de Windows Forms para C# y Visual Basic y en todos ellos pretendía usar la misma DLL o biblioteca de clases.

    Pero la solución buena ha sido creando una DLL (proyecto del tipo Class Library), crear un paquete de NuGet y usar ese paquete como referencia en lugar de una referencia al proyecto de tipo class library.

    Decirte que esa referencia, al proyecto, sí que funciona en los proyectos de tipo consola o de tipo Windows Forms, tanto para VB como para C#, pero no si el proyecto es de .NET MAUI.

    Te lo explico por si alguna vez te pasa esto… para que no te calientes la cabeza ni pierdas todo el tiempo que yo he perdido.

    Y para muestra, el proyecto ElizaNET y el correspondiente Eliza MAUI (los enlaces van al repositorio de GitHub), que ambos usan una DLL compilada para .NET 7.0 y que funcionan a la perfección (salvo los bugs que se puedan producir en esa biblioteca de clases, que algunos pueden surgir).

    Esos dos proyectos usan el código publicado en NuGet de Eliza gcnl Library que ahora va por la versión 1.0.2.

    El código fuente de esa DLL (o paquete de NuGet) está en este enlace (dentro del repositorio ElizaNET).

    Y esto es todo… espero que te sea de utilidad. Esa es la intención.

    Nos vemos.
    Guillermo

  • 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

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