jueves, 22 de mayo de 2014

Comunicar Formularios

 

Introducción


Existen varias formas pasar información entre formularios, especialmente si queremos hacerlo sin generar una fuerte dependencia entre estos.

Este mismo tema lo había abordado en artículos anteriores por lo que retomaremos el análisis de las distintas formas de lograr la comunicación sin generar dependencia entre los forms

Los artículos anteriores en los cuales he tratado el tema:

Comunicar formularios de forma desacoplada

Comunicar formularios MDI

Para ejemplificar haremos uso de un form que permite listar y editar productos de la base de datos Northwind.

image

Analizaremos 3 formas de comunicar formularios y enviar datos entre ellos:

  • Usando Interfaces
  • Usando eventos
  • Usando el evento FormClosed

 

Usando interfaces


Una interfaz permite definir un contrato entre clases, permitiendo que una invoque la funcionalidad de cualquier otra que respete ese contrato definido.

Recordemos que los formularios en definitiva no son mas que clases que se instancian por lo que puede aplicarse los mismos conceptos de POO (Programación orientada a objetos).

La implementación de esta técnica se encuentra en la búsqueda de un proveedor en el form de edición de los productos.

image

El primer paso será definir la interfaz

image

siendo implementada por el formulario padre receptora de la información seleccionada por el usuario

SNAGHTML5a01d235

El form padre será quien instancie el form hijo pasando su instancia por parámetro en el constructor, además de algún otro valor adicional de ser necesario, como en este caso un filtro para limitar los ítems visualizados en el grid de selección.

 image

 

Desde el form hijo (frmFindSupplier) se define el constructor que recibirá los parámetro

SNAGHTML5a09bacf

La variable “caller” contendrá la instancia del form padre que implementa la interfaz, mientras que “_supplierName” tendrá el input del usuario para filtrar las entidades.

Al seleccionar un ítem del grid se dará por seleccionada la entidad y se enviara la acción al form padre a través de la instancia invocando el método definido en la interfaz.

image

Primero se valida que exista selección en el grid, se recupera la entidad seleccionada pasándola como parametro al método Selected() definido en la interfaz, por ultimo se cierra el formulario. El form padre recibe el valor seleccionado y actualiza los controles o entidades que hagan falta.

La secuencia completa quedaría de esta forma

SNAGHTML5b152bbf

  1. El form padre (frmEditProductos) implementa la interfaz.
  2. En el botón de búsqueda se crea la instancia del form hijo (frmFindSupplier), pasando como parámetro en el constructor la instancia del forma padre (utilizando this)
  3. El form hijo recibe en el constructor los valores por parámetro
  4. Se selecciona un ítem del grid y se invoca al método de la interfaz
  5. El form padre recibe la selección y actualiza los datos

Como ventaja se puede mencionar que cualquier form que implemente la interfaz podrá reutilizar la funcionalidad de búsqueda implementada al no quedar acoplados los formularios que interactuan.

 

Usando eventos


Permite enviar una acción directa al form que se subscriba al evento.

El ejemplo va a estar representado en la comunicación del form de edición de productos y la búsqueda de categorías.

image

Partamos analizando la implementación del form hijo (frmFindCategory), este expone el evento, que es lanzado cuando se selecciona una categoría del grid

SNAGHTML5a76cd3

Para definir datos específicos en el intercambio de información se crea una clase que hereda de EventArgs

image

 

Desde el form padre (frmEditProductos) simplemente se debe adjuntar al evento la instancia del form hijo

image

 

Repasemos como seria la ejecución en secuencia

SNAGHTML5c710fe

 

  1. El form hijo expone el evento, utilizado para informar la selección a quien lo haya invocado.
  2. Se define una clase que hereda de EventArgs para poder pasar información adicional como argumento del evento.
  3. El form padre que realiza la búsqueda crea la instancia del forma hijo y se adjunta al evento, además crea el método que recibirá la acción.
  4. Cuando se selecciona un ítem del grid se valida si alguien esta adjunto en el evento y se invoca.

 

Actualizar los datos al cerrar el form (evento FormClosed)


Para actualizar un grid luego de una acción en otro form podría utilizarse eventos existentes, como ser el FormClosed, con este evento se puede realizar una acción al cerrar un form

image

 

Analicemos los pasos

SNAGHTMLaeed38d

 

  1. En el form padre (frmAdminProducts) instancia el form hijo (frmEditProductos) y se adjunta el evento de cierre del form
  2. Cuando se presiona el boton de aceptar o cancelar se devuelve el DialogResult cerrando el form, esto lanza el evento FormClosed
  3. Desde el form padre se atrapa el evento y se realiza la recarga de los datos del grid

 

Descarga


El articulo fue desarrollando usando Visual Studio 2012, la base de datos es Sql Compact (.sdf)

Durante la compilación se descargaran las dependencias por medio de Nuget.


[C#]
 

26 comentarios:

  1. Hola que tal, no comprendo muy bien el uso con eventos, podria subir un ejemplo más sencillo modificando un textbox desde otro,,,Gracias!!!

    ResponderEliminar
  2. hola Juan

    pero que seria exactamente lo que no quedo claro, porque en el ejemplo si bien no es un textbox estoy actualizando un label y la propiedad de la entidad que se edita

    digo, no es un textbox pero un label se le parece mucho

    saludos

    ResponderEliminar
  3. Ok, disculpa, voy a hacer más pruebas y veré porque no me sale,y ya entonces te notificaré de los problemas que tuve gracias, y tienes mucha razón con lo del label,,, gracias...

    ResponderEliminar
  4. Hola que tal de nuevo, pues ahora lo intente con delegate y me funciono también, gracias por la ayuda porque tu ejemplo me ayudo a investigar más, a lo mejor no sabía por donde empezar y con tu artículo pude solucionar mi problema gracias.!!!!!!!

    ResponderEliminar
  5. Hola que tal de nuevo, pues ahora lo intente con delegate y me funciono también, gracias por la ayuda porque tu ejemplo me ayudo a investigar más, a lo mejor no sabía por donde empezar y con tu artículo pude solucionar mi problema gracias.!!!!!!!

    ResponderEliminar
  6. hola Leo ! podras hacer alguna entrada acerca de clickonce!

    Gracias por tus aportes y saludos

    ResponderEliminar
  7. Hola Leandro Estoy en un proble nose si puedas ayudarme enviandome un tutotial o manual para hacer un reporte con subreport(rdlc) estoy buscando han la web y no encuentro nada. por favor ayudame

    ResponderEliminar
  8. ha leandro estou usando sql server 2008 y visual studio 2010 aplicacion escritorio aydam con un toturial de Reportes y subreporte

    ResponderEliminar
  9. hola Deyvi

    buscas algo como esto

    Building Subreport in Reporting Services

    si bien alli conecta el reporte directo a los datos podria trabajarse de la misma forma si usas un reporte local conectado a un dataset tipado o coleccion

    saludos

    ResponderEliminar
  10. Hola Leandro.
    mi sonsulta no tiene nada que ver con el tema. Quisiera que me ayudes con una duda, tengo un form .NET 2012. deseo que los usuarios envien correos electrónicos a Help Desk desde cualquier cuenta de correo ya sea hotmail, gmail e incluso los correos creados con un dominio privado de cualquier empresa.
    es posible hacer eso?,tienes un ejemplo?

    ResponderEliminar
  11. hola Marcos

    si cuentas con un servicio de SMTP con el cual conectarte para enviar los mail claro que podrias

    aqui
    MailMessage - Envia mail con GMail (1/3)

    envio mail usando el smtp de gmail, pero si tienes el de hotmail o algun otro tambien es valido
    el tema es que necesitaras de una cuenta con la cual autenticarte, ya que no permiten enviar mail anonimos

    saludos

    ResponderEliminar
  12. Hola Leandro, como estas, oye en el ejemplo de las interfaces veo que hay una clase(creo) que se llama Supplier... void Selected(Supplier supplier);... mi pregunta es como defines esa clase o que es... se que tiene que ver con proveedores pero no entiendo... Gracias

    ResponderEliminar
  13. hola JCLamer

    veras que hay un archivo IFindSupplier
    alli se define la interfaz que el form debe implementar para poder comunicarse con el otro form

    la entidad que se uso en este caso es la de Supplier (proveedor), pero puedes usar la que tu necesites, o un valor simple como un string, int, etc
    mientras lo definas en la interfaz

    saludos

    ResponderEliminar
  14. Primero que todo agradecer por esos aportes tan valiosos que nos brindas a todos, en ocasiones me atraso mucho en el desarrollo talvez de algo "sencillo" pero me gusta que sea de calidad y por eso siempre consulto tu blog.

    Mi pregunta. Defines este codigo public frmEditProductos(int productId)
    : this()
    {
    Product prod = ProductRepository.GetById(productId);
    _product = prod;
    }
    pero en que escenario o parte del codigo se utiliza porque no le encuentro donde..

    ResponderEliminar
  15. hola Eyder

    alli lo que haces es recuperar la entidad producto en base al id que llega en el constructor del formulario de edicion

    como veras el producto se asigna a la variable definida a nivel del formulario, con esto en el Form_load podrias poner los valores de las propiedades en los controles

    basicamente en el constructor recuperas la entidad de la db y en el load del form asignas los controles para mostrar los datos

    saludos

    ResponderEliminar
  16. Muy buen articulo me sirvio mucho. Hay algo que no entiendo como lo hiciste es cuando casteas o convertis explicitamente el DATABOUNDITEM como tipo Supplier, como lograste sobrecargar el operador explicito. No puedo ver el codigo ya que tengo una version de Visual mas antigua que la version con la que subiste las soluciones

    ResponderEliminar
  17. hola German

    el DataBoundItem es una propiedad del row del grid que devuelve la instancia que se bindeo a esa row cuando se generaron las rows, no hay ninguna sobrecarga porque no hay ningun metodo

    si asignas al DataSource del grid una List entonces el item puede castearlo a ese tipo

    si asignas un datatable entonce el DataBoundItem podrias castearlo al DataRowView

    saludos

    ResponderEliminar
  18. Gracias, ya comprendi.
    Ahora una pregunta algo mas tonta, que propiedades aplicas para el titulo de las ventanas que es marron y las letras en blanco? se ve bueno

    ResponderEliminar
  19. hola German

    en realidad es un banner gris

    alli uso un label al cual le defino la propiedad AutoSize = true
    y la propiedad Dock = Top

    despues es solo cambiar el color del fondo y la fuente

    saludos

    ResponderEliminar
  20. Por casualidad no tienes el ejemplo en vb .net, por otro lado estoy dando los primeros pasos para cambiarme a c# algun material que me puedas sugerir para hacerlo de la forma correcta.

    ResponderEliminar
  21. Hola Leandro, muy buenos todos tu ejemplos!, la verdad que aprendí mucho con tu blog, Seguí así. Muchas Gracias!

    ResponderEliminar
  22. Buenas. metodo me aconsejas para pasar una instancia de una clase de un form padre a hijo y viceversa ?? gracias por la ayuda. Saludos

    ResponderEliminar
    Respuestas
    1. hola
      puedes aplicar la misma tecnica descripta en el articulo, que sea un valor simple o una instancia de clase no varia
      puedes pasar en el constructor o en algun metodo que exponga el form hijo la intancia de la clase
      y desde el form hijo al padre teniendo la instancia de este ultimo puedes invocar un metodo pasandole por parametro la instancia, aunque recuerda que esta se pasa por referencia por lo que si la creas desde el padre al pasarla al hijo y este modificarla tambien altera los valores en el padre
      saludos

      Eliminar
  23. excelente trabajo este blog me ha sido de gran ayuda, saludos!

    ResponderEliminar