Etiqueta: c#

  • Utilidad para invertir las asignaciones de controles a objeto y viceversa (ReordenarAsignaciones)

    Pues eso, hay ocasiones en las que en el código asigno los datos de una tabla a los controles del «formulario» (quien dice formulario dice página XAML, etc.), sí, sé que se puede hacer con DataBinding, pero… casi siempre prefiero usar el modo manual ya que así parece que tengo más control con lo que hago y, de hecho, en algunas ocasiones el DataBinding no va como debería, al menos eso me ha pasado en varias páginas de Xamarin.Forms. No sé si tú lo harás así, pero yo suelo hacerlo con bastante frecuencia, será por la forma de trabajar que tengo. ?

    Te explico:
    Digamos que tengo una tabla de una base de datos, que he convertido con la utilidad Generar las clases (de VB o C#) de una tabla de SQL Server o Access (mdb) en la que tengo asignada en una variable (por ejemplo, LaFactura) el contenido de la tabla Facturas y quiero asignar el contenido de ese objeto a los diferentes controles, haría algo como esto para asignar los valores de LaFactura a los controles:

    /// <summary>
    /// Mostrar la factura en los campos.
    /// </summary>
    private void MostrarLaFactura()
    {
        chkFacActiva.IsChecked = LaFactura.Activa;
        txtFacActividad.Text = LaFactura.Actividad;
        txtFacAdultos.Text = LaFactura.Adultos.ToString();
        txtFacAgente.Text = LaFactura.Agente;
        txtFacCuantasReservas.Text = LaFactura.CuantasReservas.ToString();
        txtFacCuantosPagos.Text = LaFactura.CuantosPagos.ToString();
        txtFacDescuento.Text = LaFactura.Descuento.ToString("0.##");
        txtFacFechaFactura.Text = LaFactura.FechaFactura.ToString("dd/MM/yyyy HH:mm");
        txtFacHoraActividad.Text = LaFactura.HoraActividad.ToString("hh\\:mm");
    }

    Y tengo este otro método para hacer el caso contrario (asignar al objeto LaFactura el valor de los controles):

    /// <summary>
    /// Asignar los campos a la factura para guardar.
    /// </summary>
    /// <returns>True si algo no va bien.</returns>
    private bool AsignarLaFactura()
    {
        LaFactura.Activa = chkFacActiva.IsChecked;
        LaFactura.Actividad = txtFacActividad.Text;
        LaFactura.Adultos = txtFacAdultos.Text.AsInteger();
        LaFactura.Agente = txtFacAgente.Text;
        LaFactura.CuantasReservas = txtFacCuantasReservas.Text.AsInteger();
        LaFactura.CuantosPagos = txtFacCuantosPagos.Text.AsInteger();
        LaFactura.Descuento = txtFacDescuento.Text.AsDecimal();
        LaFactura.FechaFactura = txtFacFechaFactura.Text.AsDateTime();
        LaFactura.HoraActividad = txtFacHoraActividad.Text.AsTimeSpan();
    
        return false;
    }

    En el método MostrarLaFactura las asignaciones las hago de la forma habitual, es decir, asigno a los controles los datos que quiero mostrar, por ejemplo, si es fecha le asigno de la forma dd/MM/yyyy, etc.

    El caso especial es cuando lo hago al revés: AsignarLaFactura, que debo convertir el contenido de los controles al formato adecuado, en este caso utilizo para las fechas, horas y cifras con decimales unos métodos de extensión que tengo definidos para hacer esa tarea (que empiezan con As y tienen el formato AsTIPODATOS), esto último no es parte de la utilidad que me he fabricado, pero… la tiene en cuenta ?

    Hacer esto manualmente, que es como lo hacía hasta hace 2 días, es tedioso y, por supuesto se pueden producir errores, que modificas tras el aviso de Visual Studio, pero… es, ¿cómo decirlo?, un peñazo por no decir co**zo. ?

    Y me puse a fabricarme una utilidad (sí, en C#) para hacer eso, por ahora es muy simple y en las asignaciones no contempla que haya comentarios, pero… todo se andará.

    Las asignaciones que convertir se indican como argumentos en la línea de comandos, yo lo que hago es tener el proyecto abierto en Visual Studio y en la parte de DEBUG le asigno lo que se indicará en la línea de comandos (ver la captura 1), al hacerlo de esta forma (indicando los valores a convertir como argumentos de la aplicación), hay que tener en cuenta que los valores asignados al array args del método Main se hacen de esta forma:
    ladoIzquierdo = ladoDerecho, de forma que si pones: chkFacActiva.IsChecked = LaFactura.Activa; esta será las asignaciones al array args:
    args[0] = "chkFacActiva.IsChecked"
    args[1] = "="
    args[2] = "LaFactura.Activa;"

    Y esto es lo que tengo en cuenta, por eso aún no contemplo los comentarios, ya que analizo el contenido del array args de tres en tres valores:

    for (int i = 0; i < args.Length - 2; i += 3)

    Pero eso ya lo arreglaré en la próxima revisión.

    Figura 1. Los argumentos de la línea de comandos del proyecto

     

    Dicho esto, no me queda mucho más que decir ?

    Solo ponerte el enlace al proyecto publicado en GitHub: ReordenarAsignaciones, el nombre en realidad tendría que ser InvertirAsignaciones, pero… así es como lo creé inicialmente y… seguramente se quedará así ?

    Nota:
    En el repositorio de GitHub incluyo las clases con las extensiones que te he comentado y muchas más.
    El código de Extensiones está tanto para Visual Basic (el original) como para C# (el convertido).

    También he creado un paquete de NuGet que he definido como Tool de .NET 6 de forma que lo puedas instalar si tienes instalado el SDK de .NET 6 o superior.
    De esa forma lo podrás tener como una utilidad de .NET y no preocuparte de instalarlo (extraer el código ejecutable en una carpeta) y asignar el path a ese directorio para poder usarla desde cualquier línea de comandos.

    El paquete de NuGet se llama igual: ReordenarAsignaciones y este enlace te llevará a la página de NuGet donde tengo ese «paquete».
    Notar que no es necesario instalarlo en un proyecto de Visual Studio, simplemente instalarlo usando la línea de comandos:
    dotnet tool install --global ReordenarAsignaciones --version 1.2.0
    Esto te instalará la versión que tengo a la hora de escribir esto, pero en la página de NuGet te muestra siempre qué tienes que hacer para instalarlo.

    Para actualizar el «paquete» siempre es el mismo código independientemente de la versión:
    dotnet tool update --global ReordenarAsignaciones

     

    Espero que te sea de utilidad, esa es la intención ?

    Y si te parece bien, acuérdate de invitarme a un cafelito virtual mediante un donativo/donación con PayPal. Usando este enlace o este código QR:

    Gracias ??

    Nos vemos.
    Guillermo

  • 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

  • Ejemplos de Google Cloud Natural Language para consola y .NET MAUI

    Pues eso… aquí te dejo el código de una clase (Frases) para analizar un texto usando la API de Google Cloud Natural Language y un par de proyectos para usar esa clase. Los proyectos son para una aplicación de consola y para dispositivos usando .NET MAUI. Todo el código está para C#.

    No te voy a explicar mucho por aquí, salvo lo indicado en el siguiente párrafo, pero te dejo todo el código fuente (para C#) en este repositorio de GitHub.
    También incluyo algunas explicaciones y problemas que he tenido para usar la clase en el proyecto para .NET MAUI (no muchos, pero…)

    Algunos trucos en el código de .NET MAUI

    Un par de cosas que siempre suelo poner en los proyectos para .NET MAUI, porque no tienen la misma funcionalidad que con Xamarin.Forms, son:

    1. Definir el tamaño de la ventana para Windows, ya que en .NET MAUI la ventana se muestra enorme y no recuerda el tamaño último.
      Esto lo hago en el constructor de la clase App.
    2. Hacer que el control Frame se vea al completo (no se corte por la parte inferior).
      Esto lo consigo si en el StackLayout usado después del Frame se le deja un margin mínimo de 2.

    Además, he añadido el código para simular un Expander ver figura 1).
    Este expander lo utilizo para mostrar u ocultar la lista de textos de prueba.

    Otra cosa interesante es usar un objeto Task (usar otro proceso) cuando se pulsa en el botón de analizar, con idea que se muestre el texto mientras está analizando el texto y no se quede «congelada» la ventana.

    Este es el código del evento Clicked del botón de analizar:

    private async void BtnAnalizar_Clicked(object sender, EventArgs e)
    {
        txtResultado.Text = "";
    
        string tmp = txtTexto.Text;
        if (string.IsNullOrEmpty(tmp))
        {
            MostrarAviso("Por favor indica el texto a analizar de al menos 3 caracteres", esError: true);
            txtTexto.Focus();
            return;
        }
    
        text = tmp;
        HabilitarBotones(false);
    
        await Task.Run(() =>
        {
            MostrarAviso("Analizando el texto...", esError: false);
            frase = Frases.Add(text);
    
            BtnMostrar2.Dispatcher.Dispatch(() =>
            {
                // Inicialmente mostrar todo sin tokens
                BtnMostrar2_Clicked(null, null);
            });
            QuitarAviso();
        });
    
        HabilitarBotones(true);
    

    En los métodos llamados desde Task.Run se tienen en cuenta el Dispatcher de los controles que se modifican, con idea de que no den problemas al hacerlo entre hilos diferentes.

    Este es el código de los métodos QuitarAviso y MostrarAviso que modifican una etiqueta y un StackLayout.

    private void QuitarAviso()
    {
        LabelAviso.Dispatcher.Dispatch(() => { LabelAviso.IsVisible = false; });
        grbAviso.Dispatcher.Dispatch(() => { grbAviso.BackgroundColor = Colors.Transparent; });
    }
    
    private void MostrarAviso(string aviso, bool esError)
    {
        grbAviso.Dispatcher.Dispatch(() =>
        {
            if (esError)
            {
                grbAviso.BackgroundColor = Colors.Firebrick;
            }
            else
            {
                grbAviso.BackgroundColor = Colors.SteelBlue;
            }
        });
        LabelAviso.Dispatcher.Dispatch(() =>
        {
            LabelAviso.Text = aviso;
            LabelAviso.IsVisible = true;
        });
    

    Algunas capturas

    Aquí tienes un par de capturas de la app para .NET MAUI en funcionamiento, en la figura 1 está funcionando en Windows (usando el expander), en la figura 2 antes de poner el expander y en la figura 3 en un móvil con Android (antes de poner el expander), en iPhone no me funciona (tampoco el resto de los proyectos que tenía, así que, no he podido hacer captura).

    Figura 1. En Windows con el expander

    Figura 2. En Windows

    Figura 3. En Android

    Te recomiendo que leas el post anterior para ver cómo crear un cliente de Google Cloud Natural Language y poder usarlo en estos proyectos, en ese post indico que el código es para Visual Basic, pero los pasos a seguir son los mismos para Visual Basic que para C#.


    Espero que te sea de utilidad.

    Nos vemos.
    Guillermo