domingo, 6 de septiembre de 2009

Comunicar formularios de forma desacoplada

Introducción


El objetivo de esta guía es demostrar como posibilitar la comunicación de formulario de una forma optima, haciendo uso de buenas practicas, y además bajando al mínimo el acoplamiento entre los formulario.

Para cumplir el objetivo es que se hará uso de interfaces, las cuales permitirán desacoplar la comunicación entre formulario.

 

Comunicación simple entre formularios


En este ejemplo se confeccionara una utilidad simple, básicamente se procederá a la apertura de un formulario, y la escritura cuadros de texto.

 

Primer Paso – Creación de los formularios

Lo primero que será necesario crear son los dos formulario los cuales intervendrán en la comunicación, esta operación se hace de forma simple como seguramente ya es conocida por todos. Los mismos contaran con sus respectivos cuadros de texto, y botones que permitirán las acciones entre ellos

 

Segundo Paso - Definición de la interfaz

En al interfaz se definirá la acción que será llevada a cabo en la comunicación, en este caso sera algo simple como copiar el contenido del formulario hijo al padre

Para ello se ha creado un archivo de nombre IForm.cs, el cual contendrá dicha definición.

public interface IForm
{
	void ChangeTextBoxText(string text);
}

como podrá preciarse es muy simple solo define el contrato que permitirá luego desacoplar las interfaces

 

Tercer Paso – Implementación de la interfaz, llamada al formulario hijo

La interfaz anteriormente creada será implementada por el formulario del cual se quiere recibir la acción, en este caso será el form principal, o sea quien realiza la llamada.

public partial class Form1 : Form, IForm
{
    public Form1()
    {
        InitializeComponent();
    }

    #region IForm Members

    public void ChangeTextBoxText(string text)
    {
        TextBox1.Text = text;
    }

    #endregion

    private void Button1_Click(object sender, EventArgs e)
    {
        Form2 form2 = new Form2();
        form2.Show(this);
    }
}

Hay que resaltar varias partes en esta sección de código:

- se notara en la primer línea como el formulario define la implementación de la interfaz

- la región establecida en el código, denota la implementación concreta de la misma, entre las líneas 8 al 15

También hay que remarcar como se realiza la apertura del formulario hijo, debe notarse el uso del parámetro en el método Show(), es allí donde se especifica quien será el owner, en este caso se hace uso de this ya que el formulario donde estamos en ese momento será quien realiza la apertura.

 

Cuarto Paso – Comunicación desde el formulario hijo

En esta ultima sección se visualizara como el formulario hijo envía datos al padre.

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void Button1_Click(object sender, EventArgs e)
    {
        IForm formInterface = this.Owner as IForm;

        if(formInterface != null)
            formInterface.ChangeTextBoxText(TextBox1.Text);
    }

}

En el código se puede apreciar claramente el uso de la propiedad Owner junto al this que en este caso representa al Form2.

Es interesante además remarcar la necesidad de castear la propiedad, en este caso particular se realiza mediante el uso de “as”
Es muy útil hacer uso de este ya que ante una imposibilidad o error de casteo la aplicación no producirá un error, en este caso simplemente la variable obtendrá el valor null, es por ello que se hace uso del “if” para preguntar si pudo realizar la conversión de tipos.

 

Conclusión


Bueno después de analizar el ejemplo verán como por medio de un simple interfaz se logra desacoplar las dependencias entre formulario facilitando la comunicación entre ellos, la simple definición de un contrato asegura que el formulario hijo pueda interactuar ya no solo con un forma padre único, sino con cualquier otro formulario que lo utilice e implemente la interfaz.

[C#]
[VB.NET]

117 comentarios:

  1. Justo lo que estaba buscando! Gracias por compartir, seguí así.

    Me estoy recorriendo todo tu blog, encontré justo lo q necesito para la facultad.

    ResponderEliminar
  2. hola Leandro Tuttini !

    mi nombre es daniel y necesito de tu ayuda tengo un problema con un aplicativo web. no mantiene las session las cambia estoy paso en la parte de la publicacón del aplicativo en el servidor de producción en la parte de desarrollo no realiza esto que puede hacer. gracias por tu ayuda.

    ResponderEliminar
  3. daniel de nuevo


    mi correo es danielhernandezcorona@gmail.com

    gracias por tu ayuda.

    ResponderEliminar
  4. hola Daniel disculpa la tardanza en contestar es que no vi los comentarios.

    Te aconsejaria que realices la consulta en el foro de MSDN, yo participo alli:

    Foro ASP.NET

    saludos

    ResponderEliminar
  5. Muchas gracias Leandro, me ha funcionado a la perfección!

    Un saludo desde Barcelona

    ResponderEliminar
  6. Hola,
    me gustaría saber como leer el dato del textbox es decir solo quiero utilizar el valor establecido en el textbox en otro formulario

    ResponderEliminar
  7. hola Any

    Bueno justamente lo que planteas es lo que no recomiendo hacer.

    Como habras visto referenciar un control directametne desde otro formulario agrega un gran acoplamiento entre estos, por eso justamente el uso de propiedades.

    Bueno justo en este ejemplo no lo explico a este punto ya que se trata de la comunicacion entre hijo a padre, pero si en este otro:

    [WinForms] – Pasaje de información formulario hijo

    Igualmente si necesitas hacerlo de forma directa al control, puedes seleccionar el TextBox del form de origen, presiona F4 para ver sus propiedasdes, y busca una de nombre "Modifiers", valida que este asiganda en Public.

    Con esto deberias poder acceder al textbox desde el otro formulario, si es que tienes la instancia del mismo.

    saludos

    ResponderEliminar
  8. Gracias Leandro he resuelto mi problema

    ResponderEliminar
  9. hola Lenadro

    He resuelto la parte de leer los datos en los formularios, con tu ejemplo de pasaje de información mediante constructores pero mi pregunta es que si se puede leer los datos de la misma forma desde el Load del formulatio tanto como de un metodo?

    ResponderEliminar
  10. hola Any

    Claro que puedes

    Si desde el constructor has asignado los valores que se pasan por parametro a variables privadas del formulario, estos estan accesibles a todo el form, no los al evento Load.

    En los ejemplos use este evento porque lo comun es que se tome alli y se muestre la info, pero si lo necesitas en alguna operacion de click de un boton tambien puede usarlo.

    por ejemplo:

    public class Form2
    {
    private int _id;

    public Form2()
    {
    InitialiceComponente();
    }

    public Form2(int id) : this()
    {
    _id = id;
    }

    private void btnSave_Click(...)
    {
    MessageBox.Show(string.Format("Se edita el id: {0}", _id));
    }

    }

    saludos

    ResponderEliminar
  11. Querido Leandro, primero y principal gracias por tus aportes, me sirven muchisimo !!
    Te molesto con una consultita respecto de esto y quizas un poco mas.Estoy desarrollando una aplicacion en VBnet con una arquitectura de 3 capas, lo empece asi por que dicen que es lo correcto para que la aplicacion sea escalable, adaptable y bla bla bla, pero no veo ejemplos en donde realmente reutilizen ese codigo, parece que todo lo dejan armado para tal fin pero luego no es facil "usarlo", y sobre todo se habla muy poco de la capa de presentacion. Y este articulo tuyo me sirvio darme una idea de algunas cosas entre formularios pero mi problema es con el formulario principal. Osea si yo mañana cambio algo en la capa de negocios o datos, puede reemplazarla y listo (reinstalando el ensamblado y apuntando a esa nueva version, etc ) pero y la capa de PRESENTACION??, Ejemplo: inicia la aplicacion y va a el formulario principal, este supongamos que tiene dos botones con dos opciones, pero luego en el futuro quiero agregarle mas botones con mas opciones. Tu ejemplo me sirvio porque estoy haciendo que esos botones habran formularios de forma desacoplada con el principal, de esta manera mañana podria cambiar unos de estor forms y el principal no se entera, pero... CON EL PRINCIPAL COMO HAGO??,... porque la aplicacion inicia AHI. Otra que se me ocurre pero no logro resolver es que en verdad NO INICIE ahi, que se llama tambien de forma desacoplada al principal. Bueno si me podes dar una idea te agradesco muchicismo.

    ResponderEliminar
  12. hola Adrian

    lo empece asi por que dicen que es lo correcto
    para que la aplicacion sea escalable, adaptable


    Te has olvidado lo principal, la reutilizacion, modelar en capas tiene por funcionalidad de tu modelo se pueda reutilizar
    cuando codificar la persistencia del cliente o facturas, las defines en un lugar que puede ser invocadas desde cualquier punto de tu aplicacion y siempre es la misma funcionalidad la cual sabes que funciona

    ademas aunque no lo apliques facilita la creacion de Unit Test, para asegurar la calidad del software que desarrollas

    la capa de PRESENTACION??

    Esta parte no se si la entendi del todo, ya que cambiar la presentacion en una arquitectura en capas es similar a cambiar cualquier otra, solo desarrollas la nueva presentacion y la conectas al negocio, estas deberian conectarse por un medio independiente, ahora si a la capa de negocio le pasas controles directamente eso esta rompiendo la arquitectura, deben ser siempre tipos de datos simple, o por ahi clases, colecciones, o si lo deseas dataset tipados.

    CON EL PRINCIPAL COMO HAGO??

    Sino entendi mal, aqui el planteo esta mas orientada a realizar tareas previas a iniciar la aplicacion

    Winforms, realizar tareas antes de inicializar aplicacion

    En el articulo veras que en vb.net se puede definir el Sub Main para realizar tareas previas alli podrias definir que form principal iniciar, asignado al Application.Run() la instancia segun cierta logica que determines

    Espero haber entendido bien la consulta, y que sea util estas respuestas

    saludos

    ResponderEliminar
  13. e copiado el código linea tras linea y lo e revisado carácter x carácter y todo se ve = incluso las referencias, pero np me anda, en el :::: if (formInterface != null) :::: pasa defrente:

    k puede pasar

    ResponderEliminar
    Respuestas
    1. A mi me pasa exactamente lo mismo, simplemente no hace el cast de this.owner a iForm

      Eliminar
  14. Muy Bueno!, una vez mas Leandro con la magia! :P

    ResponderEliminar
  15. Disculpa por la pregunta :$, pero que se entiende por acoplamiento entre/de formularios?? y que problemas implica?

    Saludos y Gracias

    ResponderEliminar
  16. hola Axel

    Por acoplamiento me refiero a cuando dos objetos requieren uno del otro para poder funcionar.

    O sea, si un formulario accede a otro por su nombre entonces estan acoplados y si se realiza algun cambio en uno de los form puede que el otro deje de funcionar.

    Con esto no aseguras la reutilizacion, ya que por cada uno que quiera acceder a la funcionalidad del otro debas fijar los nombres, si un form sera accedido por, digamos 10 forms distintos deberas poner el nombre de cada uno
    En cambio de la forma que lo propongo en el articulo no hace falta eso, con solo implementar la interfaz ya esta listo, el form hijo al que se invoca entiende la interfaz y sabe como trabjar con esta.

    Por ejemplo el form hijo cambia el valor del TextBox1, que pasa si se te ocurre renombrar el control, tu aplciacion ya no compila y debes ir a cada form hijo que acceda a ese control para cambair el codigo, ese es el problema que se intenta resolver, un cambio en el form no afecte al resto.

    saludos

    ResponderEliminar
  17. Excelente Leandro MUchas Gracias la verdad! Envidio gente dedicada como tu.

    ResponderEliminar
  18. Hola mi nombre es Darling, tengo una duda, resulta que tengo un mdi y desde ese llamo a un formulario y lo hago hijo de este, pero a su vez abro otro formulario desde el hijo y quiero pasar desde este valores al formulario que lo llama, que me puedes recomendar para esto?
    Agradezco tu respuesta

    ResponderEliminar
  19. hola Patricia Vargas

    bien comentas que usas formularios MDI, a lo cual imagino que estos forms que abres son mdi child, o sea estan dentro del ambiente mdi

    si es asi recuerda que deberias cambiar algo la tecnica

    Comunicar formularios MDI

    cuando dices que desde el segundo salto o sea el segundo form que abres quieres pasar informacion al quien lo llama te refiers al form padre de este, o al primero de todos?

    seria bueno aclararlo porque cambia las tecnicas aplicadas, si es padre directo puede aplicar esta misma tecnica, pero si el primero de todos podrias usar

    [Winforms] Singleton - Pasar datos entre formularios

    saludos

    ResponderEliminar
  20. Hola Leandro, te vengo siguiendo desde la comunidad de MSDN, mi duda es analoga a la entrada que publicaste...pero al revés...
    es decir:
    Desde un formulario Hijo (MDIChild) como levanto datos que estan ponele en un label en un formulario padre (MDIParent).
    Probe con:
    private void NewReg_Load(object sender, EventArgs e)
    {
    BSDocumentum frm = new BSDocumentum();

    textBox1.Text = frm.toolStripStatusLabel2.Text;

    ...}

    Pero como el toolStripStatusLabel2 ya habia sido modificado por otro metodo, lo que me devuelve es el valor "inicial".
    Se que esto es lo tuyo...por eso acudo a vos...espero tus comentarios.
    Saludos y gracias de antemano

    ResponderEliminar
  21. hola .

    pero en este ejemplo no estas reflejando lo que comentas, alli sigues asignando al form principal (o quien lanza al otro form) el valor del form hijo, podrias seguir usando lo mismo que se aplica aqui

    ahora bien si la idea es enviar info al forma hijo podrias usar el constructor o propiedades

    [WinForms] – Pasaje de información formulario hijo


    saludos

    ResponderEliminar
  22. leandro...no hay problema...mil gracias por la predisposicion pero el problema lo resolvio siguiendo la logica de "si la montanña no va a Mahoma..." por lo que en lugar de que desde el frmB levante datos del frmA. Hice que el frmA pase los datos al frmB:
    con algo así:
    FormB frmB = new FormB;
    formB.txt1.text = this.label1.text ;

    Si mal no recuerdo...de ultima despues paso el codigo posta...


    Saludos y mil gracias!

    ResponderEliminar
  23. Hola Leandro

    mi pregunta es la siguiente:
    en esta partee de tu codigo de Vb
    Dim _formInterface As IForm = CType(Me.Owner, IForm)

    el me.owner devuelve el propietario del formulario hijo, mi problema es que esto me devulve de propietario el mdi que tengo y no el formulario principal de donde llame al form hijo.

    Como podira hacer para que me devolviera el nombre del formulario que lo llamo y no el del MDI

    ResponderEliminar
  24. hola Ronal

    el tema es que si estas en un entorno MDI deberias aplicar la otra tecnica

    Comunicar formularios MDI


    saludos

    ResponderEliminar
  25. hola Leandro mi pregunta es es buena practica realizar este método si trabajas en 3 capas?

    ResponderEliminar
  26. hola diego

    este metodo nada tiene que ver con un desarrollo en 3 capas

    es solo para aplicar a nivel de interfaz de usuario en los formularios, que despues uses 3 capas, solo 2, o quizas te conectes directo a la db desde el formulario, eso es indistinto y esta tecnica en nada lo afecta

    saludos

    ResponderEliminar
  27. Hola que tal... por favor me puede ayudar? al implementar la comunicacion de formularios con interfaz, me sale un error y es: MantGrupoProductos.Formularios.frmProveedores' no implementa el miembro de interfaz 'MantGrupoProductos.Clases.IForm.CargarDato(string)'

    ademas de esto al ejecutar, en el if(objIForm != null) siempre me da null. por favor ruego que me ayuda.. gracias..

    ResponderEliminar
  28. hola proyemulti

    pero el error deja bien claro que el form padre no implementa la intefaz de forma correcta

    puedes hacer boton derecho sobre la interfaz que defines en el Inherits que defines al lado de la clase del form y en el menu en las opciones de refactor esta para implementar la interfaz de forma automatica

    Imagen

    saludos

    ResponderEliminar
  29. Gracias a tu ejemplo Leandro... pude hacer el envio de imagenes de formularios a formularios...

    ResponderEliminar
  30. hola leandro gracias por tu blog es genial, me ha sacado de muhos aprietos, este ejemplo de comunicacion desacoplada es muy bueno descargue tu codigo y lo corri y funciona perfectamente, solo que cuando lo implemento en mi programa me marca un error porque estoy trabajando con un mdi parent, es en la parte del me.owner, me podrias dar un tip de como solucionar ese problema, saludos

    ResponderEliminar
  31. hola azael

    no analizaste el otro articulo que esta justo arriba de este

    Comunicar formularios MDI

    saludos

    ResponderEliminar
  32. si ya lo cheque leandro pero me sale un error que dice que no puede convertir el tipo medi parent a la interfaz, espero me puedas resolver esa duda por favor

    ResponderEliminar
  33. hola azael

    pero el form padre esta implementando la interfaz ?

    porque se supone que esa propiedad parente contiene la instancia del form mdi la cual debe implementar la interfaz para poder realizar la accion

    saludos

    ResponderEliminar
  34. ya lo pude resolver leandro jejej era un errorsito del cual no me habia dado cuenta, ahora tengo una nueva duda que no tiene nada que ver con este tema, es sobre como llenar un combobox desde una base de datos, tendras algun articulo relacionado con esto?, saludos y gracias por responder

    ResponderEliminar
  35. hola azael

    aqui
    [WinForms] Edición Empleados

    cargo el combo de estudios desde los datos de una tabla, quizas puede servir de ejemplo

    saludos

    ResponderEliminar
  36. Hola leandro

    Si estoy en un modulo como puedo deshabilitar un boton de una forma

    en vb6 era forma.boton.enabled =false

    Ahora en vb.net no me deja

    quize implementar tu codigo, pero por ser modulo no me da un owner

    Espero me puedas ayudar...

    Saludos

    ResponderEliminar
  37. hola Cesar

    usar el nombre del form para acceder a sus controels no es la forma adecuada

    si analizaste este articulo vera que si implementas una interfaz podrias acceder a la instancia del form padre para invocar un metodo que anule el boton

    pero el acceso al boton es siemrpe local, desde el form hijo usas un interfaz para invocar al metodoq eu realiza la accion sovre el otro form

    saludos

    ResponderEliminar
  38. Muchisimas gracias Leandro tu blog me ha ayudado mucho en mi trabajo y este post en especial me ayudo mucho

    ResponderEliminar
  39. Muy Bueno , el Post me sirvio muchisimo ...Gracias y Felicitaciones ...

    ResponderEliminar
  40. Muy Bueno , el Post me sirvio muchisimo ...Gracias y Felicitaciones ...

    ResponderEliminar
  41. Muy Bueno , el Post me sirvio muchisimo ...Gracias y Felicitaciones ...

    ResponderEliminar
  42. Leandro,
    soy nuevo en este mundo de la programación con muy poca experiencia.
    buscando di con tu blog muy bueno.
    Muchas gracias de antemano por tu ayuda.

    lo principal de este comentario es el siguiente.
    Como puedo declarar mas variables en el IForm para poder pasar mas información a la misma vez?
    he tratado de hacerlo solo pero me he encontrado con varios errores.
    podrías echarme una mano?
    Saludos y gracias de antemano.

    ResponderEliminar
  43. hola Burro

    es que no declaras ninguna variable porque no la necesitas

    a lo sumo defines una propiedad en la interfaz para que la implemente el form padre y asi asignarle un valor desde el form hijo

    pero no usas variables para comunicar datos entre forma, solo propiedades y metodos

    si vas a pasar mucha info podrias definir un metodo con varios parametros, o sino una coleccion o lista generica

    saludos

    ResponderEliminar
  44. Hola ....
    En cada archivo de interface (IForm) debo tener una unica Sub ?? ...lo digo por que quiero agregar otra Sub al Iform y me devuelve error en los formularios que implemento com si deberia usar todas las sub contenidas en la interface ??

    ResponderEliminar
  45. hola Efrain

    el IForm puede definir cuantas Sub necesites

    pero el Form (o clase) que inplemente la interfaz debera declara todas las sub que el contrato defina

    si en el IForm defines 2 sub en el fom vas a tener que declararlas a las dos

    saludos

    ResponderEliminar
  46. Hola Leandro Tuttini, antes agradecerte por el apoyo que brindas a la comunidad de desarrolladores. Me estoy iniciando en vb studio 2008 y me toca realizar una aplicación vinculada a sql server 2008. En un formulario tengo un combobox que recoge datos de sql (desde una tabla proveedores, la cual tiene otros campos como rut, direccion, telefono etc..). en el mismo formulario, Al lado del combobox, tiene varios textbox los cuales no se pueden modificar por el usuario, solo deben mostrar información. Lo que necesito es que al seleccionar desde el combobox el nombre de un proveedor, automáticamente me llene los textbox con los otros datos de la tabla (rut, teléfono, dirección etc ..) esto ultimo, no logro hacerlo. ¿Es posible que puedas ayudarme? Desde ya muchas gracias

    ResponderEliminar
  47. hola Claudio

    para lograr esto deberias definir el evento SelectionChangeCommitted del combo
    en ese evento deberias tomar el SelectedValue, imagino el combo le defines el DisplayMember y ValueMember asi solo tomaras el id del proveedor, no filtres nunca por el nombre o descripcion

    entonces solo queda que realices un SELECT a la tabla filtrando por el id del proveedor

    imagino parametro y definir el WHERE sabes como hacerlo

    saludos

    ResponderEliminar
  48. Leandro MUCHAS GRACIAS !! he aprendido hacer esto gracias a ti y me ha resultado de maravilla.un abrazo.

    ResponderEliminar
  49. Hola Leandro Tuttini, te escribo nuevamente para comentarte que la ayuda que me brindaste la ves pasada me ha funcionado perfecto y nuevamente te lo agradezco. Hoy acudo a ti por lo sgte:
    En un formulario tengo un combobox con 5 opciones en la lista. La ultima opción dice "Cheque" refiriéndose a la forma de pago, necesito que la persona cuando seleccione esta ultima opción, se habiliten 4 checkbox para que el usuario pueda seleccionar alguno de ellos. actualmente los tengo en modo Disable desde las opciones de los checked.
    Intente lo sgtesin resultado:

    if combobox.selectedvalue= "cheque then
    checkbox3.enable = true

    else

    msgbox "Error"

    Con este código, solo me muestra el error.

    Deben habilitarse Si y solo Si el usuario selecciona la opción de cheque desde el combobox. Crees que puedes ayudarme? desde ya muchas gracias, un abrazo.

    ResponderEliminar
  50. hola Claudio

    pero como sabes que el SelectedValue del combo devuelve el texto "cheque" ?
    como asignas el Datasource del combo? le defines el ValueMemeber, porque si lo haces quizas le estes indicando un campo de id o key de la entidad por lo que cheque sea un id = 1

    si pones un breakpoint en el codigo y pasas el mouse por SelectedValue que valor observas ?

    saludos

    ResponderEliminar
  51. Hola Leandro, gusto en saludarte, en realidad, lo que hice fue agregar a las listas desde el panel de configuración del combo, el nombre cheque, no lo extrae de ninguna base de datos. Quizás debería crear una tabla en sqlserver con estos datos y llamarlos para que se muestren en el combo, de esta manera quizás me funcione.que crees? ahora,aprovechando, tengo una duda tremenda.estoy intentando crear una aplicación para las ordenes de compra. Para ello, he hecho lo sgte. en un form he puesto un textbox(Para el NºOC)el cual debe ser único y autoincrementable desde la base de datos. tengo un combo1 que extrae datos de proveedores desde bd y muestra valores relacionados con proveedor en textbox, tengo un combo2 que expone las condiciones de pago y tengo un datagrid1. Aquí es donde tengo el problema. Me gustaría saber si es posible ir llenando (escribiendo) sobre las celdas del datagrid, la cantidad, el precio etc .. que algunas celdas se autocompleten al ir escribiendo y poder guardar desde ahí. El datagri estaría para escribir información y llenar la bd,no para visualizar datos como es de costumbre. por otra parte,nose como hacer para que varios items en una sola orden de compra estén asociados a un solo NºOC. porque el datagrid va por linea y cada linea me tomaría un NºOC distinto. Lo he pensado mucho y no se me ocurre como hacerlo. Ojala puedas ayudarme. Desde ya te agradezco mucho tu tiempo y ayuda. Hay muy pocos maestros que tienen ese espiritu servicial.

    ResponderEliminar
  52. hola Claudio

    ahh ok creas los items en tiempo de diseño, puedes hacerlo de esta forma si crees que los items no van a cambiar, si los items pueden variar entonces define una tabla en tu db

    sobre las celdas del grid puedes escribir y realizar acciones en el evento CellEndEdit para tomar lo ingresado y completar el resto de las celdas

    tambien podrias usar esta otra tecnica
    [DataGridView] KeyPress detectar ENTER y búsqueda

    saludos

    ResponderEliminar
  53. hola leandro

    es justo lo que buscaba,pero tengo un problema no con tu codigo ya que es excelente

    mi problema es este, quiero hacer lo mismo pero con el evento Activated del form, osea yo creo una variable publica en el form1 , hago click en un boton , me manda al form2
    en ese form hay un datagrid hago click en un celda y me captura el codigo y lo asigno a la variable publica del form1 , se cierra el form2 y queda el form1 pero o me manda el codigo que seleccione en el grid del form2

    nota : si es que ejecuto primero el form2 y mando el codigo al form1(osea por el evento load del form1) si me sale, pero yo quiero hacerlo con el actived u otro evento que haga lo que pido

    ayudaaaa , de antemano muchas gracias

    ResponderEliminar
  54. hola leandro

    es justo lo que buscaba,pero tengo un problema no con tu codigo ya que es excelente

    mi problema es este, quiero hacer lo mismo pero con el evento Activated del form, osea yo creo una variable publica en el form1 , hago click en un boton , me manda al form2
    en ese form hay un datagrid hago click en un celda y me captura el codigo y lo asigno a la variable publica del form1 , se cierra el form2 y queda el form1 pero o me manda el codigo que seleccione en el grid del form2

    nota : si es que ejecuto primero el form2 y mando el codigo al form1(osea por el evento load del form1) si me sale, pero yo quiero hacerlo con el actived u otro evento que haga lo que pido

    ayudaaaa , de antemano muchas gracias

    ResponderEliminar
  55. hola leandro

    es justo lo que buscaba,pero tengo un problema no con tu codigo ya que es excelente

    mi problema es este, quiero hacer lo mismo pero con el evento Activated del form, osea yo creo una variable publica en el form1 , hago click en un boton , me manda al form2
    en ese form hay un datagrid hago click en un celda y me captura el codigo y lo asigno a la variable publica del form1 , se cierra el form2 y queda el form1 pero o me manda el codigo que seleccione en el grid del form2

    nota : si es que ejecuto primero el form2 y mando el codigo al form1(osea por el evento load del form1) si me sale, pero yo quiero hacerlo con el actived u otro evento que haga lo que pido

    ayudaaaa , de antemano muchas gracias

    ResponderEliminar
  56. hola Hector

    pero haces que el form1 implemente una interfaz la cual usas para desde el form2 llamarla pasando el valor de la celda seleccionada ?

    debes pasarle al form1 con algun metodo de la interfaz el valor de la celda del form2 para asignarlo a la variable

    imagino que desde el form1 es que abres el form2 por eso la instancia puedes asignarla, no veo que necesites ningun Activated ni nada raro

    saludos

    ResponderEliminar
  57. Hola Leandro, un consulta en el caso de reemplazar el textbox y el button del ejemplo por un checkbox, suponiendo que form1 al dar click en checkbox del form1 (checked = true) muestre el form2 y para form2 al dar click en el button retornar el checkbox de form1 vuelva a des habilitarse (checked = false).

    Como aplicaría en ese caso ???
    Gracias por tu atención.

    ResponderEliminar
  58. hola Leopoldo

    podrias usar para hacer mas simple el evento FormClosing del Form2 pero controlandolo desde el form1 asi cuando cierres el form podrias cambiar el estado del check

    actualizar formularios

    desde el form1 cuando creas la instancia te adjuntas al evento para detectar el cierre del form2 y actualizar el check

    saludos

    ResponderEliminar
  59. Hola que Tal, quisiera saber como realizar algo parecido, pero con 3 Formularios, es decir, Tengo un Form1 que llama a un Form2 y el a su vez un Form3 y desde alli quiero enviar Datos al Form1 es posible realizar esto, como? espero puedan Responder a mi Pregunta de Antemano Gracias.

    ResponderEliminar
  60. Hola Leandro tengo una consulta, mira yo tengo un formulario que no es MDI que lo he definido como contenedor de varios formularios, para pasar datos directo desde un formulario hijo al formulario contender es util lo expuesto en tu blog al utilizar el owner del formulario, sin embargo el formulario hijo utiliza varias librerias entre ellas una clase para el acceso a la base de datos, quisiera que desde esta clase active el progressbar que se encuentra en el contendedor con el objetivo de indicar el tiempo que demora en realizarse una consulta BD, sin necesidad de estar escribiendo codigo repetitivo en las invocaciones..

    Espero me puedas guira un poco agradeceria tu ayuda..

    ResponderEliminar
  61. hola Santiago

    podrias hacer que la clase exponga algun evento para informar avance en la tarea
    entonces el form al crear la instancoa se adjunta al evento y ante la accion del mismo muestra el progress

    lo que no creo es que puedas conocer el tiempo de demora que tendra una query, ya que la db no informa este dato
    podrias si mostrar un progress que avance indicando trabajo, quizas con estilo marquee, pero no sera un avance real solo indicaras que se esta realizando la tarea

    saludos

    ResponderEliminar
  62. Hola Leandro

    En primer lugar gracias por tus aportes.

    Estoy intentando implementar un interfaz para hacer una comunicación entre formularios no acoplada.

    Mi problema es que estoy usando formularios que se incrustan en un Panel del formulario principal y cuando utilizo el Show(this) o ShowDialog(this)obtengo el mismo resultado, una excepción del tipo:
    System.InvalidOperationException

    Información adicional: Un formulario que no es de nivel superior no se puede mostrar como un cuadro de diálogo modal. Quite el formulario de los formularios primarios que lo contengan antes de llamar a showDialog.

    Me puedes decir como podría hacerlo o que es lo que estoy haciendo mal.

    Gracias.

    ResponderEliminar
  63. hola Roberto

    prueba implementar la tecnica pero como lo planteo aqui

    Comunicar Formularios

    alli explico como usar el constructor del forma para pasar la instancia en lugar de usar el owner con el show() de esta forma no necesitas mostrar el form para poder pasar la instancia

    saludos

    ResponderEliminar
  64. Uno de los pocos artículos hispanoparlantes de calidad sobre el uso buena práctica para la comunicación entre controles de formulario, sin publicar los mismos y totalmente desacoplados uno del otro.

    Sin declaración de variables innecesarias, y además, el uso de Interfaces.

    Estaba buscando complementar éste método y con ésto, finiquito.

    Por ahí hay otros buenos tuyos explicando los MDI y patrón: Singleton aplicado a Formularios.

    Agradecido, Tuttini por éstos grandes aportes.

    Saludos cordiales.

    ResponderEliminar
  65. hola saludos una pregunta como puedo comunicar dos form y ellas estando en una MDI gracias por tu respuesta

    ResponderEliminar
  66. hola landos

    no entendi, esos dos forms de forma interactuan?
    el MDI contiene a esos dos forms?

    saludos

    ResponderEliminar
  67. NO ME SIRVIÓ ABSOLUTA MENTE NADA..., Usted no explica bien, No muestra todo el proyecto Para guiarse de el solo explica la parte técnica

    ResponderEliminar
  68. hola Kevin

    gracias por el feedback, te comento que este articulo fue mejorado recientemente, no se si pudiste analizarlo

    Comunicar Formularios

    quizas ese sea un poco mas util
    saludos

    ResponderEliminar
  69. hola
    Como puedo enviar datos del formulario hijo al padre??? Siendo q el form hijo esta en un panel q lo tiene el padre??

    gracias

    ResponderEliminar
  70. hola Oscar

    porque usas un Formulario para ponerlo dentro de un Panel, porque no usas un User Control

    un control es similar a un form pero sin la barra de titulo, puedes instanciarlo y asignarlo a la coleccion de controles

    saludos

    ResponderEliminar
  71. Hola

    tengo un Form1 y un Form2 como puedo hacer invisible un boton en el Form1 al presionar otro boton desde el Form2.

    ResponderEliminar
  72. hola OJMA

    si tienes la instancia del form1 desde el form2 podrias usar

    form1.Hide();

    aunque no aconsejaria hacerlo de esta forma sino aplicar la tecnica de este articulo en donde el form1 expone una interfaz que puedes invocar desde el form2 para realizar la accion

    quien se oculta es el propio form1 ya que implementaria algo como ser

    public interface IOcultar{
    void Ocultar();
    }

    y lo implementas en el form1

    public void Ocultar(){
    this.Hide();
    }

    ese metodo es el que invocas desde el form2 aplciando la tecnica de este articulo describe

    saludos

    ResponderEliminar
  73. Hola Leandro Tuttini,

    que pasa si tengo 2 textbox que reciben informacion, 1 recibe el tipo de proveedor y el otro cargo de empleado.

    no me permite utilizar la misma interfaz para obtener la informacion desde los form maestros(tipoproveedor,cargoempleado)

    como podria hacer en ese caso, tengo que crear una nueva interfaz si es que tengo que obtener datos de 2 form diferentes???

    muchas gracias, espero tu respuesta.

    ResponderEliminar
  74. hola Dennis

    en el caso que planteas vas a tener que definir dos interfaces diferentes

    una para el form que retorna el proveedor y otra para el empleado
    ya que por lo que comentas son dos forma distintos lo que devuelves esta informacion

    saludos

    ResponderEliminar
  75. Hola Leandro:
    Quisiera consultarte como puedo realizar una interfaz de conexión en visual estudio para conocer los estados de las entradas y salidas de un PLC de marca siemens por TCP.

    desde ya muchas gracias,

    ResponderEliminar
  76. Hola Leandro

    Entonces debo llegar a la conclusión que no es posible usar una misma interfaz mas de una vez en un mismo formulario.

    Saludos Gracias por responder.

    ResponderEliminar
  77. hola Yohel

    imposible no es, pero si lo haces estas rompiendo con la resposabilidades de la interfaz en cada operacion
    podrias definir una unica interfaz que exponga metodos para devolver provedores y empleados, pero no se si es correcto hacerlo

    si tu evaluas que lo es entonces podrias implementarlo de esa forma, quizas en dos metodos

    public interface IForm{

    void EmpleadoSelected(Empleado entity);

    void ProveedorSelected(Proveedor entity);

    }

    entonces el form implementa ambas a pesar que quizas solo requiera una entidad y no ambas

    saludos

    ResponderEliminar
  78. hola Claudio

    la verdad no tengo experiencias programando plc
    pero en el foro se respondio una pregunta como la que planteas

    PROGRAMACION CON PLC

    saludos

    ResponderEliminar
  79. Leandro.
    no funcionan los link de descarga de los codigos fuentes.

    ResponderEliminar
  80. hola Dante

    ya estan actualizados los link del articulo


    saludos

    ResponderEliminar
  81. Hola Leandro

    muchas gracias por el aporte.

    Saludos

    ResponderEliminar
  82. Hola leandro podrías actualizar los links para hacer la descarga?.
    Gracias.

    ResponderEliminar
  83. hola Sergio

    pero estan actualizados, el link te redirecciona a OneDrive

    aunque recomendaria que mejor analices
    Comunicar Formularios

    saldos

    ResponderEliminar
  84. hola leandro tu ejemplo lo puce dentro de un Menu con MdiParent para abran las ventanas y sena hijas


    y me sale este error

    Un formulario que no es de nivel superior no se puede mostrar como un cuadro de diálogo modal. Quite el formulario de los formularios primarios que lo contengan antes de llamar a Show.

    ResponderEliminar
  85. hola jorge

    recuerdo que si a un form le asignas el MdiParent no puedes usar el ShowDialog(), no puede ser un form modal

    solo puedes usar el Show() cuando el form es un mdi child

    saludos

    ResponderEliminar
  86. Disculpa, pero no logro entender la explicación :/
    Tengo 2 forms y quiero habilitar un boton en el form2 desde el form1
    ¿Como puedo hacerlo??

    ResponderEliminar
  87. hola JOseRGIO

    cual de los forma que mencionas actua como hijo o padres ?

    podrias evaluar el articulo
    Comunicar Formularios
    quizas se entienda mejor

    saludos

    ResponderEliminar
  88. Muy bueno.
    También ejemplos básicos: http://tupagina.comuf.com/

    ResponderEliminar
  89. queria ver si me podia ayudar con un error que me da a la hora de llamar o mostrar un usercontrol en frame el error me da a la hora de escribir el nombre del usercontrol.mdiparant y no lo muestra y otra consulta como se programa un boton salir en un usercontrol ya que con close() no funciona. gracias.

    ResponderEliminar
  90. si Form Principal es MDI y Form2 es hijo... entonces no funciona. Que deberia cambiar?

    ResponderEliminar
    Respuestas
    1. hola
      Implementalo como comento aqui
      Comunicar Formularios
      esta tecnica aplica aunque el principal sea MDI ya que se usa el constructor
      saludos

      Eliminar
  91. hola Leandro me gustaría mucho que me ayudaras con el siguiente código lo que pasa el que tengo un formulario donde hay un botón de búsqueda este botón abre otro formulario que contiene un datagrid con varios registros lo que necesito es k al darle click a un registro se cangue la infoemacion en varios texbox de otro formulario.
    Public Sub cargardatos(ByVal vector_de_datos)

    My.Forms.eventos.t_id_clien.Text = vector_de_datos(0)
    My.Forms.eventos.t_nit_client.Text = vector_de_datos(1)
    My.Forms.Eventos.t_dir_Client.Text = vector_de_datos(2)
    My.Forms.Eventos.t_pag_Client.Text = vector_de_datos(3)

    End Sub
    Private Sub DGclientes_DoubleClick(sender As Object, e As EventArgs) Handles DGclientes.DoubleClick

    Eventos.MdiParent = My.Forms.MDIPrincipal

    Dim Fila_Seleccionada As Byte = CByte(Me.DGclientes.CurrentCell.RowIndex)
    Dim vector_de_datos(3) As String

    vector_de_datos(0) = Me.DGclientes.Rows(Fila_Seleccionada).Cells(0).Value.ToString
    vector_de_datos(1) = Me.DGclientes.Rows(Fila_Seleccionada).Cells(4).Value.ToString
    vector_de_datos(2) = Me.DGclientes.Rows(Fila_Seleccionada).Cells(5).Value.ToString
    vector_de_datos(3) = Me.DGclientes.Rows(Fila_Seleccionada).Cells(6).Value.ToString

    Me.Hide()

    My.Forms.Eventos.Show()
    Me.Dispose()

    Me.cargardatos(vector_de_datos)
    este es el código me funciona pero me abre dos formularios uno con los datos y otro sin ellos lo que necesito es que me abra un solo formulario con la información del registro del grid.

    ResponderEliminar
    Respuestas
    1. hola
      No se porque usas My.Forms, entiendo es algo de vb.net, pero no lo recomiendo, deberias instanaciar el form y hacer el show del mismo
      Si tienes un form de evento deberias usar

      Dim frm As New Eventos
      frm.MdiParent = Me.MDIPrincipal
      frm.Show()

      o sea los instancia y muestras el form

      saludos

      Eliminar
  92. hola, disculpa tengo una duda, en mi caso:
    yo manejo en mi aplicación un form principal el cual tiene un menú con el cual llamo a los controles de usuario que vienen siendo mis pantallas para cada uno de mis modulos y en algunos casos me veo obligado a llamar a un form secundario desde el control de usuario, y ocupo que el form secundario me regrese valores al control de usuario, de que forma podría recibir los valores del segundo form? es que implemente su código pero note que solo funciona de Form a form por la instrucción "Dim _formInterface As IForm = CType(Me.Owner, IForm)" o existirá alguna forma para que el "Me.Owner" sea un control de usuario en lugar de Form?

    ResponderEliminar
  93. Leandro muchas gracias por el aporte , saludos!!

    ResponderEliminar
  94. muy buen post!! , muchas gracias Leandro por compartir este conocimiento, saludos

    ResponderEliminar
  95. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  96. Hola Leandro, cómo te va?? Antes que nada mil gracias por tus posts!! Tengo un problema con un formulario MDIChild, realicé la codificación para otro formulario no contenido por el padre y funcionó a la perfección, ambos tienen el objetivo de des habilitar el botón que los invoca, pero el primero que menciono no funciona. Me podrías dar una mano por favor? Ya me quedé algo estancado jaja. Saludos!

    ResponderEliminar
  97. Muchas gracias!!! Me fué de gran utilidad. Saludos.

    ResponderEliminar
  98. Hola leandro, excelente tu trabajo, estoy con una aplicacion C#, que manda a ejecutar otra (de la cual no tengo idea en que fue prgramada, he tratado con Windows Inspector pero no logro determinar las clases de las Ventanas que se ejecutan), la cosa es que luego de mandarla a ejecutar obtengo su Id y logro ejecutar ciertas opciones de la misma usando SendKeys y el mouse_event, sin embargo al querer establecer por ejemplo el valor de campos fecha en la aplicacion externa no tengo control, tambien al traerme la data usuando el Clipboard.GetDataObject() he tenido inconvenientes, no se si me seguis, podeis ayudarme .. ?

    ResponderEliminar
    Respuestas
    1. hola

      Entiendo que para acceder a los datos de la otra aplicacion deberias acceder al proceso de la misma, la unica forma que conozco es por medio implementar la tecnica de hooking

      Manipulate any program by using C#

      saludos

      Eliminar
  99. Hola Leandro, buen día. Antes que nada muchas felicidades por tus pots me han ayudado bastante para realizar mis aplicaciones en C#, tengo un problema en el paso 4, IForm formInterface = this.Owner as IForm; esta parte siempre da da null como resultado por lo que no se ejecuta el metodo que necesito. ¿Cuál sería la razón? solo adapte el código que muestras para poder activar un timer que uso en mi Form2 desde mi Form3 al momento de que este se cierra pero esto nunca sucede debido a que siempre es null, espero me puedas ayudar, gracias.

    ResponderEliminar
  100. Excelente Leandro! buen aporte, me sirvio de mucha ayuda, gracias

    ResponderEliminar
  101. Hola Leandro aún hoy aplique tu código y funciona a la perfección pero necesito ahora la comunicación inversa, es decir del formulario principal pasar dos variables al secundario. Con el constructor lo pude conseguir pero recarga el formulario cada vez que lo hago (haciendo un efecto flash indeseado), lo que necesito es actualizar un formulario ya instanciado. Intenté con este ejemplo pero el Owner no puedo definirlo desde el Show() porque ambos formularios están ya abiertos y el formulario hijo es el que tiene que recibir el dato. Básicamente el padre le pasa la ruta y el hijo carga una imagen. Podrías orientarme como actualizar el pictureBox con un dato del formulario padre? He buscado en la red y todos los ejemplos son para abrir formularios, no para formularios que ya están instanciados. Muchas gracias.

    ResponderEliminar
  102. Excelente aporte amigo Leandro!. Gracias por compartir.

    ResponderEliminar
  103. Excelente el aporte! Una consulta,como se podría implementar en 3 forms?. Supongamos que son 1,2 y 3, donde 2 es hijo de 1 y 3 es hijo de 2 y quiero pasar el dato desde 3 hacia 2 y 1.

    ResponderEliminar
  104. Me echan una mano, no puedo instanciar a mi clase interface desde mi formulario primcipal MDI en la parte de Iactualiza1 formInterface = this.Owner as Iactualiza1; siempre retorna null

    ResponderEliminar
  105. Gracias por el articulo. Yo deseaba desde otro formulario adicionar filas al datagrid del formulario principal con los datos de las cajas de texto del otro,formulario, lo resolví.

    ResponderEliminar
  106. saludo Leandro soy novato en la programacion el problema mio puede ser sencillo, tengo 1 button y 2 textbox
    ejemplo en el button quiero que sea un numero ejemplo el ("1") bueno lo siguente es que quiero es que marque el ("1") donde este el cursor que este el textbox......gracias

    ResponderEliminar