sábado, 17 de octubre de 2009

[ASP.NET] Pasar información entre User Control

 

Introducción


El desarrollo modular de aplicaciones web requiere la confección de componentes que permitan encapsular ciertos compartimientos que serán reutilizados, o que necesitan ser tratados de una forma unificada para facilitar la mantenibilidad del desarrollo.

Es por eso que en ciertas ocasiones el uso de User Controls es una buena práctica, aunque un aspecto no menor es la comunicación entre estos componentes encapsulados con el resto de la aplicación, o con otros componentes.

En este texto explicare como lograr la comunicación entre dos User Control, pasando datos de uno a otro de una forma desacoplada.

 

Diseño


El planteo se basará en la utilización de dos users control muy simples que estarán contenidos en una misma página web.

El primer user control encapsulará una grilla la cual cargara un listado de empleados.

El segundo contiene una serie de Textbox que serán utilizados para visualizar el registro seleccionado del primer user control.

 

User Control – Listado


Este estará formado por un control GridView.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

namespace WebUserControlsCommunicated
{
    public partial class ucGrid : System.Web.UI.UserControl
    {
        public delegate void GridSelectorCommandEventHandler(GridSelectorCommandEventArgs e);
        public event GridSelectorCommandEventHandler GridSelectorChanged;

        public class GridSelectorCommandEventArgs
        {
            public int Id { get; protected set; }
            public string Nombre { get; protected set; }
            public string Cargo { get; protected set; }

            public GridSelectorCommandEventArgs(int id, string nombre, string cargo)
            {
                this.Id = id;
                this.Nombre = nombre;
                this.Cargo = cargo;
            }
        }


        public DataTable DataSource { get; set; }


        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                GridView1.DataSource = this.DataSource;
                GridView1.DataBind();
            }
        }

        protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            int Id = Convert.ToInt32(GridView1.SelectedRow.Cells[1].Text);
            string nombre = Convert.ToString(GridView1.SelectedRow.Cells[2].Text);
            string cargo = Convert.ToString(GridView1.SelectedRow.Cells[3].Text);


            if (GridSelectorChanged != null)
                GridSelectorChanged(new GridSelectorCommandEventArgs(Id, nombre, cargo));

            
        }
    }
}

Los puntos importantes a destacar del código serian:

- línea 30, define la propiedad que permitirá asignar el origen de datos que se usará para cargar el GridView. Esta propiedad será utilizada en el evento Page_Load del user control, asignando el contenido.

- líneas 12 y 13, en las mismas se define el handler y evento que permitirán que la información  de los items seleccionados del GridView viajen desde el interior del user control hacia la página.

- líneas 15-27, definen el argumento del evento que será usado para realizar el pasaje de los datos seleccionados en la grilla. Es por medio de este argumento que se podrá recuperar los valores elegidos, ya que desde fuera del user control no se tendra acceso directo al GridView.

Habría una alternativas a esta opción, la cual consiste en dejar disponible en una propiedad los valores seleccionados, imitando un poco a las propiedades como ser el SelectedRow, o SelectedItems que poseen otro controles.

- líneas 42-53, estas defines el evento local al user control que se ejecutará al utilizar el botón de selección del GridView, básicamente será una especie de conversión de eventos, en donde un evento atrapado localmente, es transformado en un evento exterior, el cual es lanzado en la línea 50.

Como ser observara las primeras acciones son las de recuperar los valores de la columnas de la fila seleccionada, para poderlos usar como parámetros del argumento del evento que se lanzara.

Es muy importante cuando se va a lanzar un evento validar que este tenga algún método adjunto, ya que de no tener ninguno y ejecutarse este producirá un fallo, la validación por distinto de null evita este problema.

 

User Control – Listado de TextBox


Este user control contendrá una serie de TextBox, destinado a la visualización de la información seleccionada en el user control que contiene el GridView

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebUserControlsCommunicated
{
    public partial class ucTextView : System.Web.UI.UserControl
    {

        public int Id { get; set; }
        public string Nombre { get; set; }
        public string Cargo { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        public void Refresh(int id, string nombre, string cargo)
        {
            this.Id = Id;
            this.Nombre = nombre;
            this.Cargo = cargo;

            this.Refresh();
        }

        public void Refresh()
        {
            txtId.Text = Convert.ToString(this.Id);
            txtNombre.Text = this.Nombre;
            txtCargo.Text = this.Cargo;
        }
    }
}

Este control tiene bastante menos lógica que implementar ya que su funcionalidad se reduce a recibir los valores y asignarlos a los TextBox que correspondan.

Como se observa cuenta con una serie de propiedades que representan cada atributo de la entidad.

Y un método Refresh() que será el encargado de realizar en concreto la asignación de cada propiedad con su respectivo control.

 

Integración – Default.aspx


Bien llego el momento de poner todo en conjunto a funcionar.

Para ello se hará uso del formulario web, Default.aspx, es allí donde se arrastrara cada user control en el diseñador de la pagina, haciendo uso de una tabla para dar algo de formato y ubicación.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

namespace WebUserControlsCommunicated
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ucGrid1.GridSelectorChanged += new ucGrid.GridSelectorCommandEventHandler(ucGrid1_GridSelectorChanged);

            if (!IsPostBack)
            {
                ucGrid1.DataSource = CargarTabla();
            }
        }

        void ucGrid1_GridSelectorChanged(ucGrid.GridSelectorCommandEventArgs e)
        {
            ucTextView1.Id = e.Id;
            ucTextView1.Nombre = e.Nombre;
            ucTextView1.Cargo = e.Cargo;

            ucTextView1.Refresh(); 
        }



        private DataTable CargarTabla()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Id");
            dt.Columns.Add("Nombre");
            dt.Columns.Add("Cargo");

            DataRow row = dt.NewRow();
            row["Id"] = 1;
            row["Nombre"] = "Andres";
            row["Cargo"] = "Developer";
            dt.Rows.Add(row);

            row = dt.NewRow();
            row["Id"] = 2;
            row["Nombre"] = "Federico";
            row["Cargo"] = "PM";
            dt.Rows.Add(row);

            row = dt.NewRow();
            row["Id"] = 3;
            row["Nombre"] = "Leonardo";
            row["Cargo"] = "Developer";
            dt.Rows.Add(row);

            return dt;

        }

    }
}

En la línea 14 es donde se define la utilización del evento expuesto por el user control que contiene la grilla, la asignación del handler requiere de un método declarado en las líneas 22-29.

Es en este método ucGrid1_GridSelectorChanged donde se hará uso de los parámetro del argumento del evento GridSelectorCommandEventArgs, para especificar los datos al segundo user control.

Como se habrá notado en este caso se asignan las propiedades directamente al segundo user control, para llamar por ultimo el método Refresh() que realizara la asignación de estos valores dentro del control; pero también se podría haber utilizado para tal fin el método Refresh() sobrecargado con los valores de cada propiedad necesaria para desplegar la información.

[C#] 
 

49 comentarios:

  1. ¡Excelente ejemplo!

    Había experimentado antes con la comunicación de usercontrols por evento, pero solo a través de propiedades de la clase así que este ejemplo me viene muy bien.

    Lo único que hay que explicar aqui es que este codigo es para la version 3.5 del framework de .net y si se quiere aplicar a 2.0 deben declararse las propiedades completas:

    private int codigo;
    public int Codigo
    {
    get
    {
    return codigo;
    }
    set
    {
    codigo = Codigo;
    }
    }

    Si no se declaran sale el error " *propiedad* debe declarar un cuerpo porque no está marcada como abstract o extern"

    ¡¡Saludos!!

    ResponderEliminar
  2. hola vi tu ejemplo pero quiero bajar el proy y me dice que no esta disponible.

    ResponderEliminar
  3. hola Josengan

    disculpa la demora, el proyecto de ejemplo ya esta actualizado

    ahora deberias pdoer descargarlo

    saludos

    ResponderEliminar
  4. Hola, muy interesante el post sobre los user control, mi pregunta es la siguiente ... este mismo código funcionaria para windows form?, si es así no tendrás un ejemplo por ahí que puedas publicar, eso.

    Saludos...

    ResponderEliminar
  5. hola daniel

    A nivel conceptual puedo decirte que si funciona, por supuesto este ejemplo esta planteado para un desarrollo web por lo tanto el codigo asi como esta no aplica a winforms.

    Pero el uso del evento y propiedades es identico en winforms ya que no es un concepto propio de web, sino que es del .net de forma global.

    Si en tus user control defines evento y propiedades puede aplicar la misma tecnica que ves en este articulo.

    Es mas si los evento y propiedades las defines en tus controles igual que en los ejemplso tambien deberia funcionar.

    saludos

    ResponderEliminar
  6. Buenas Leandro estoy probando tu ejemplo pero en VB, pero tengo problemas con esta parte en el evento SelectedIndexChanged de gridview :

    if (GridSelectorChanged != null)

    Porque si trato de hacer algo como esto :
    If GridSelectorChanged IsNot Nothing Then

    Obtengo este error :
    'Public Event GridSelectorChanged(e As GridSelectorCommandEventArgs)' es un evento y no se puede llamar directamente. Utilice la instrucción RaiseEvent para provocar un evento.

    y por el contenido de esa condicional allí si supongo que debo usar RaiseEvent:

    RaiseEvent GridSelectorChanged(New GridSelectorCommandEventArgs(id, nombre, cargo))


    Saludos

    ResponderEliminar
  7. Sorry :( esta linea tampoco se como convertirla a VB y el resultado que arroja el conversor de C# a VB.NET es el mismo :(

    ucGrid1.GridSelectorChanged += new ucGrid.GridSelectorCommandEventHandler(ucGrid1_GridSelectorChanged);

    ResponderEliminar
  8. hola Edalo

    pero ese error no se produce porque has puesto mal la linea del if, como bien has comentado el

    RaiseEvent

    es necesario para alnzar un evento en vb.net

    pero me quedo la duda aun con este menciona el error ?

    prueba de descargar el IDE

    SharpDevelop

    con este en un click te convierte todo el proyecto de un lenguaje a otro, descarga la version 3.2, y abre la solucion con este para convertir

    saludos

    ResponderEliminar
  9. con respeto al

    ucGrid1.GridSelectorChanged += new ucGrid.GridSelectorCommandEventHandler(ucGrid1_GridS

    podria ser

    AddHandler ucGrid1.GridSelectorChanged, AddressOf ucGrid1_GridS

    AddHandler (Instrucción)

    saludos

    ResponderEliminar
  10. wow ! ! Leandro el IDE esta super.

    Resulta que todo esto :
    if (GridSelectorChanged != null)
    GridSelectorChanged(new GridSelectorCommandEventArgs(Id, nombre, cargo));

    es convertido a simplemente:
    RaiseEvent GridSelectorChanged(New GridSelectorCommandEventArgs(id, nombre, cargo))

    Sin ningún If y la manera de agregar el handler era ésta:
    AddHandler ucGrid1.GridSelectorChanged, New ucGrid.GridSelectorCommandEventHandler(AddressOf ucGrid1_GridSelectorChanged)

    Otra vez muchísimas gracias Leandro.
    Saludos y hasta luego

    ResponderEliminar
  11. hola

    lo del if validalo, porque aunque sea vb.net sino hay nadie adjunto al evento este pdorias falla sino lo verificas
    quizas debas hacerlo comparando contra Nothing, porque una cosa es la validacion y otra es el RaiseEvent

    lo del evento esta correcto, pero se que con el AddressOf podrias reducir algo el codigo

    saludos

    ResponderEliminar
  12. Hola Leandro.
    Bueno como lo había mencionado antes, ya había intentado hacer algo así:

    If GridSelectorChanged IsNot Nothing Then
    RaiseEvent GridSelectorChanged(New GridSelectorCommandEventArgs(id, nombre, cargo))
    End If

    Pero obtenía este error y ya no supe como poder saber para validarlo:

    Error 1 'Public Event GridSelectorChanged(e As GridSelectorCommandEventArgs)' es un evento y no se puede llamar directamente. Utilice la instrucción RaiseEvent para provocar un evento.

    y con respecto a lo del evento yo también creo que :
    AddHandler ucGrid1.GridSelectorChanged, AddressOf ucGrid1_GridSelectorChanged

    Es mas fácil de usar,al menos para mi :( ,ademas que la otra forma (la que puse anteriormente)nunca la termine de entender :(

    Saludos

    ResponderEliminar
  13. Hola Leandro, Me pareció muy interesante el ejemplo.
    Al tratar de implementarlo en mi maquina me esta dando null el GridSelectorChanged en las siguientes lineas:

    if (GridSelectorChanged != null)
    GridSelectorChanged(new GridSelectorCommandEventArgs(Id, nombre, cargo));


    ¿Tenes idea de porq pasa esto?

    ResponderEliminar
  14. hola Patricia

    Habras visto que en el user control se define un evento

    public event GridSelectorCommandEventHandler GridSelectorChanged;

    si desde la pagina no se adjuntas al mismo, es que nadie requiere la notificacion, por lo tanto estara en null y el evento no se lanzara


    en la pagina Default.aspx veras la linea

    ucGrid1.GridSelectorChanged += new ucGrid.GridSelectorCommandEventHandler(ucGrid1_GridSelectorChanged);

    alli es donde se adjunta el evento, si tienes esa liena ya no tendras un null cuando se lance el evento desde dentro del control

    saludos

    ResponderEliminar
  15. Hola Leandro, me ha servido mucho tu artículo. Gracias.
    Una pregunta. ¿Como usar un UpdatePanel para no refrescar toda página?
    Gracias de nuevo

    ResponderEliminar
  16. hola

    bueno la pregunta es un poco general

    Información general sobre el control UpdatePanel

    quizas si analiza la doc sobre el uso del componente ayude a entender su uso

    saludos

    ResponderEliminar
  17. Cordial Saludo leandro, le escribo parfa comentarle la siguiente situacion:

    Estoy desarrollando una ventana de mensajes con un user control todo esto en c#, y lo que ha sido el dolor de cabeza para mi es llamar un metodo que se encuentra en el control desde mi pagina aspx, no puedo hacer en mi pagina web aspx una instancia del user control por lo cual no puedo acceder a este metodo..


    Lenadro he leído todo sus comentarios y su blog pero aun no encuentro nada que me ayude.

    le agradezco si tienes la respuesta a la mano, que pueda facilitármela.

    ResponderEliminar
  18. hola fercho

    esta ventana de mensajes como la implementas? es un window.open() de javascript, usas jquery, o el modalpopup de ajax toolkit

    porque segun sea el caso la implementacion de la llamada cambia

    ademas esta pagina es la que contiene el control, o es la pagina padre quien debe comunicarse con la pagina hijo invocando el control

    saludos

    ResponderEliminar
  19. Hola Leandro

    Quise agregar el Gridview dentro de un UpdatePanel pero cuando quiero hacer la devolución de la información de User Control al web Form no lo hace y si quito ese UpdatePanel si lo hace
    Te ha pasado algo similiar?

    Gracias de antemano.

    ResponderEliminar
  20. hola Arenales


    que implicaria esta "devolución" ?

    el gridview esta dentro del user control? como comunicas ese user control con la paginas aspx, usas eventos ?

    porque deberias crear un eventos custom para pasar datos del user control a la pagina

    saludos

    ResponderEliminar
  21. Que tal Leandro

    Utilizó todo tu ejemplo incluido los eventos que nos muestras solo que el gridview (que esta en el usercontrol) lo estoy agregando dentro de un updatepanel.
    El usercontrol lo necesito para que muestre un catalogo de materias lo cual quiero que al seleccionar una materia me regrese la clave de esa materia.

    Saludos

    ResponderEliminar
  22. hola Ray

    Using the ASP.NET UpdatePanel Control with User Controls

    en principio no veo porque deberia haber problemas en usar un updatepanel dentro de un usercontrol, analiza el link a ver si da uan pista

    saludos

    ResponderEliminar
  23. Muchas Gracias Leandro... una pregunta no tienes este proyecto en vb 2010

    y que pase de cajas de texto a grilla

    Saludos

    ResponderEliminar
  24. hola Naaman

    en este caso no lo publique en vb.net
    pero podrias transformarlo si necesitas usando
    http://www.icsharpcode.net/opensource/sd/

    con este ide open source puede convertir proyecto de un lenguaje a otro con un simple click, por supuesto seguro hay que adaptar, pero la gran mayoria lo tendras en el lenguaje que necesitas

    para agregar row al grid solo es cuestion de usar el

    datagridview1.Rows.Add(New String() { Textbox1.Text})

    DataGridView adding rows and columns in VB.NET

    saludos

    ResponderEliminar
  25. Hi,Entire user control are not to expensive and by going Web Design Cochin route you almost certainly be guaranteed that your template is unique.Thanks....

    ResponderEliminar
  26. Exelente ejemplo!
    En windows forms c# como seria.. yo tengo un texbox fuera del control de usuario quisiera enviar el dato del texbox a un label q esta dentro de un control de usuario como le haria en este caso agradeseria tu respueta gracias !!!

    ResponderEliminar
  27. hola Jez

    la tecnica es la misma, para pasar info al control deberias hacer que este exponga una propiedad o metodo publico el cual puedas invocar desde fuera asignando el valor que luego sera puesto al control label que esta dentro

    si quieres notificar al form de alguna accion que se produce dentro del control entonces debes exponer evento

    o sea ya sea web o winform las tecnicas son las mismas

    saludos

    ResponderEliminar
  28. Hola leandro me da mucho gusto saludarte y bueno quería comentarte que tu ejemplo me sirvió muchísimo, solo tengo una duda...

    si deseara en vez de utilizar la clase "GridSelectorCommandEventArgs"
    dentro del "ucGrid" crear la clase aparte en un
    GridSelectorCommandEventArgs.cs
    con las propiedades y el constructor... todo exactamente igual.
    Crees que se pueda implementar??

    saludos y muchas gracias...

    ResponderEliminar
  29. hola Jessica

    claro, puedes adaptar el codigo de esa forma moviendo la definicion de la clase a un nuevo .cs

    como es un class puedes moverlo a un archivo separado

    saludos

    ResponderEliminar
  30. Leandro gracias por contestar =).
    Te cuento que ya lo implemente en una clase aparte y funciona de maravilla.
    Gracias por este ejemplo tan bueno seguiré mas de cerca información sobre delegados y eventos son realmente interesantes...

    ResponderEliminar
  31. Hola Leandro

    Espero me puedas ayudar, que sucede
    si tengo un ControUser en un formulario y desde ese control Invoco a un Formulario que me va retornar informacion.
    Como puedo enviar la informacion desde
    ese formulario al ControlUser.

    Gracias Saludos.

    ResponderEliminar
  32. hola Dennis

    invocas al form desde el user control de que forma ? lanzas un popup con javascript o realizas un redirect

    es que segun como navegas a esa otra pagina cambia como devuelves los datos

    si usas javascript podrias usar el window.opener para enviarle informacion a la pagina que lanzo el popup si usas redirect entonces quiezas debas poner los datos en el Session de asp.net para tomarlo cuand vuelvas

    saludos

    ResponderEliminar
  33. Hola Leandro

    creo que no lo mencione pero estoy trabajando con Visual Basic, quisiera una recomendacion para ese caso .

    Saludos

    ResponderEliminar
  34. hola Dennis

    que tipo de recomendacion buscas
    porque podrias aplicar esta misma tecnica

    Comunicar Formularios

    la unica diferencia es que mostrarias el form desde un user control, pero el control de la vuelta lo harias desde alli mismo por lo tanto aplica perfectamente

    en vb.net la tecnica es la misma, estos ejemplo no lo converti a vb.net pero tampoco es tan complejo usando una tool como ser
    http://converter.telerik.com/

    saludos

    ResponderEliminar
  35. Hola Leandro

    Voy a resumir lo que quiero hacer, tengo un formulario de Ingresos que se maneja segun el concepto que se elija, tengo un controluser para cada concepto, segun el concepto que se elija el formulario mostrara un control diferente.
    Por ejemplo. en el controluser tengo un boton que me abre un formulario con el maestro persona, yo elijo la persona y tendria que retornar ID y Descripcion.

    Estoy usando la comunicacion de formularios de forma desacoplada, ahora dime desde donde yo implemento la interfaz desde el formulario ingreso o desde el controluser?, lo hice desde el controluser y me retorna un error, y si lo implemento en el formulario tendria que en donde implemento la interfaz llamar a un metodo publico del controluser en donde muestre los datos, solo asi podria salir.

    Dime esa forma esta bien? o ahi alguna otra forma de pasar los datos directamente del form hijo al control user.

    Saludos.

    ResponderEliminar
  36. hola Dennis

    pero deberias poder implementarlo desde el user control, que error estas obteniendo?

    si el user control implementa la interfaz y esa instancia la pasas por parametro en el constructor la vuelta deberia invocarse al metodos de la interfaz del objeto que hayas pasado en la instancia

    saludos

    ResponderEliminar
  37. Hola Leandro

    Esto en el Control :

    Dim socio As New frmMaestroSocio
    socio.ShowDialog(Me)

    En el Form MaestroSocio :

    Dim EnviarInformacion As IObtenerSocio = CType(Me.Owner, IObtenerSocio)

    If IsDBNull(EnviarInformacion) Then
    Else

    Dim t As DataGridViewRow
    t = DataGridView1.CurrentRow

    EnviarInformacion.ObtenerInformacion(t.Cells("descripcion").Value, t.Cells("id").Value)

    Me.Close()
    End If


    Este es el error :

    No se puede convertir un objeto de tipo 'PROYECTO.frmIngreso' al tipo 'PROYECTO.IObtenerSocio'.

    Saludos

    ResponderEliminar
  38. hola Dennis

    pero el form frmMaestroSocio esta implementando la interfaz IObtenerSocio ?

    porque sino la implementa no va a poder convertir

    ademas para que haces esto
    If IsDBNull(EnviarInformacion) Then
    castear de tipo nunca va a es un dbnull, esto se usa para la base de datos

    saludos

    ResponderEliminar
  39. Hola Leandro

    Pero el frmMaestroSocio es el que manda la informacion, desde el usercontrol abro el frmMaestroSocio.

    saludos

    ResponderEliminar
  40. hola Dennis


    pero entonces no te sirve usar un owner porque no es este quien implementa la interfaz

    tienes que usar el constructor
    Comunicar Formularios

    para poder pasarle la instancia del user control que sera quien implemente a itnerfaz

    saludos

    ResponderEliminar
  41. Hola Leandro

    a cual te refieres:

    -Usando Interfaces o
    -Usando eventos

    saludos

    ResponderEliminar
  42. hola Dennis

    es indistinto puedes usar la tecnica que veas mejor se adapte a lo que quieres lograr

    quizas para seguir en la misma linea podrias usar el de la interfaz

    saludos

    ResponderEliminar
  43. Que tal Leandro.

    Muchas gracias por compartir tu conocimiento.

    Te comento hace algun tiempo integre tu codigo a un proyecto que he hecho.

    Te explico lo que hago es mostrar mis controles de usuario en un modal extender (ajaxcontroltoolkit).

    Me he dado cuenta que mi pagina se alenta a la hora de mostrar y ocultar mi modal, mi pagina se tarda mucho en cargar los datos y mostrarlos, ya sea en el web form o a la hora de cargar los datos en en control de usuario.

    No se a que se deba esto, te agradeceria si me puedes dar alguna sugerencia o como poder identificar en que parte de mi codigo causa que mi pagina responda tan lento.

    Saludos y gracias

    ResponderEliminar
  44. hola Gerardo

    recuerda que el popup en realidad esta dentro de la misma pagina por lo que este tambien se carga cuando la pagina se muestra

    si la pagina y los popup contienen mucha informacion o controles pesados como ser el GridView o similar es logico que se demore

    quizas debas rediseñar la pagina para mostrar menos informacion

    saludos

    ResponderEliminar
  45. Tengo una pequena Duda amigo, he visto que algunas web pueden abrir aplicaciones y pasar parametros usando < a href="Appl:Nombre:daniel| Apellido:juan", mi pregunta es como puedo crear un app de windowsform para que coja los parametros enviados atravez del link, uso Visual Studio 2013

    ResponderEliminar
  46. Excelente, muchas gracias Leandro como siempre de mucho apoyo.

    ResponderEliminar
  47. Sin ánimo de ofender y con intención solo constructiva, en mi humilde opinión creo que sería bueno que corrigiese en su entrada esto:
    Esto no es correcto:
    para facilitar la mantenibilidad del desarrollo
    lo correcto sería:
    para facilitar el mantenimiento del desarrollo


    ResponderEliminar