locked
¿Cómo le paso la referencia de un formulario a otro formulario que se abre a partir de este? (explico) RRS feed

  • Pregunta

  • Suponiendo que abro un formulario principal así:

    Sub Main()
         Dim forMiNuevoFormulario As New forMiFormulario
         forMiNuevoFormulario.Name = "MiNuevoFormulario"
         Application.Run(forMiNuevoFormulario)
    End If

    ...y ese formulario tiene un menú y cada opción de ese menú abre un formulario.

    A su vez dichos formularios hacen diversas llamadas a procedimientos que referencian al formulario principal (el que abro en el Sub Main).

    ¿La consulta es cómo le paso la referencia del formulario principal?

    Me parece que es asi:

    Estando en el formulario principal: CualquierFormulario.ShowDialog(me)

    Pero no me queda claro cómo recibo (uso) la referencia en dicho formulario.

    En lugar de lo anterior podria declarar la variable del formulario principal como pública pero me parece que no es lo más adecuado.


    • Editado James-2016 sábado, 21 de mayo de 2016 8:47
    sábado, 21 de mayo de 2016 8:45

Respuestas

  • "James-2016" preguntó:

    > En ese caso entiendo que el formulario retorna el resultado del botón presionado.

    El método ShowDialog devuelve un valor DialogResult que nos indica el motivo del cierre de dicho formulario. Pero cuando yo hablaba de devolver un valor, no me refería a un valor DialogResult, más bien a una propiedad pública del formulario que hayamos implementado en el mismo y cuyo valor nos interese conocer, como por ejemplo, la ruta del archivo que el usuario ha escrito en un control TextBox.

    > Por eso consultaba si al agregarle el Me a la llamada del método ShowDialog()
    > le estaba pasando la referencia al Menú Principal al cuadro de diálogo en
    > cuestión y cómo recibirla en este.
    >
    > En todo caso, la consulta es ¿Cuál es la manera correcta, recomendada, de hacer lo de arriba?

    Si a todos los formularios modales los vas a llamar desde el formulario principal de tu aplicación, entonces el asunto tiene fácil solución, porque precisamente tienes que especificar la palabra clave Me para indicar cuál es el formulario propietario del cuadro de diálogo:

         ' Llamamos a un cuadro de diálogo (formulario) cualquiera.
         Using forOpcion As New forMiOpcion()
    
             ' Mostramos el cuadro de diálogo pasándole la referencia del formulario propietario.
             Dim dr As DialogResult = forOpcion.ShowDialog(Me)
        
             If (dr = DialogResult.OK) Then
                ' Ejecutar aquí lo que proceda cuando se haya
    ' pulsado el botón Aceptar.
    Else
    ' Ejecutar aquí lo que proceda cuando se haya
    ' cerrado el cuadro de diálogo haciendo clic
    ' sobre otro botón distinto del botón Aceptar. End If End Using


    Y ahora, en el formulario que actúa de cuadro de diálogo, obtendrías la referencia del formulario propietario leyendo el valor de su propiedad Owner:

     
        ' Referenciamos el formulario propietario,
        ' aquel que ha llamado a forMiOpcion.
        '
        Dim frm As Form = Me.Owner
        MessageBox.Show(frm.Name)

    De ésta manera, ni te hace falta la "triquiñuela" comentada ni tampoco la llamada a la función GetFormMain.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    sábado, 21 de mayo de 2016 11:15
    Moderador
  • "James-2016" preguntó:

    > 1º Entonces lo que se quiera devolver del formulario se hace a través
    > de propiedades públicas declaradas en el mismo formulario, sería algo así?
    >
    > Public Property imaFoto As Image
    >

    Efectivamente. Si no tienes suficiente con las propiedades que implementa la propia clase System.Windows.Forms.Form, de la que heredan por defecto todos aquellos formularios que explícitamente crees desde el IDE de Visual Studio, puedes implementar tantos procedimientos Property que necesites para devolver o asignar los valores concretos que desees.

    > y en el cuerpo le asigno a imaFoto la imagen de un PictureBox por ejemplo.

    Una vez que tengas declarada y creada la instancia de la clase Form correspondiente, desde fuera del formulario podrás asignarle los valores a todas aquellas propiedades cuyo ámbito de visibilidad sea superior a Private:

        Dim frm As New MyForm()
        frm.imaFoto = objetoImage

    > 2º Si declaro propiedades en el formulario estas no aparecen, como en el caso
    > de los controles de usuario, en sus propiedades? (las que se ven al pulsar F4?)

    Si te soy sincero, la verdad es que nunca me he preocupado de esa cuestión, y entiendo que es correcto que no se vean las nuevas propiedades en la Ventana de Propiedades, aunque a aquellas le establezcas los atributos necesarios para que se muestren en dicha ventana, porque para el diseñador de formularios de Visual Studio (que es el que realmente necesita la Ventana de Propiedades para hacer el trabajo que le han encomendado) esas propiedades no existen.

    Debes de tener siempre en cuenta que tu estás utilizando un formulario (una clase) que hereda de otra, por lo que en dicha ventana solamente aparecerán aquellas existentes en la clase base (System.Windows.Forms.Form), que son las únicas que el diseñador de formularios entiende que existen, pero no las nuevas que implementes.

    Estas nuevas propiedades públicas que implementes (por ejemplo, en un formulario llamado MyForm), sí te aparecerán en la Ventana de Propiedades cuando otro formulario que crees herede directamente de MyForm:

    Public Class MyForm
    
        Inherits Form
    
        Private m_image As Image
    
        Public Property MyImage() As Image
            Get
                Return m_image
            End Get
            Set(value As Image)
                m_image = value
            End Set
        End Property
    
    End Class

    Ahora creamos otro formulario que herede de MyForm:

    Public Class MyForm2
    
        Inherits MyForm
    
    End Class

    Y en éste caso, sí te aparecerá la propiedad MyImage en la Ventana de Propiedades, porque el diseñador de formularios ha leído que existe en la clase una propiedad llamada MyImagen con el tipo de dato Image, tal y como muestra la siguiente captura de pantalla:

    Es como si crearas un control de usuario, pero que en lugar de heredar de la clase UserControl heredas de la clase TextBox, por poner un ejemplo. En este caso se mostrarán únicamente las propiedades de la clase TextBox, y aquellas nuevas que implementes en la clase heredada, solamente estarán disponibles en la ventana de Propiedades en aquellos formularios donde hayas insertado tu nuevo control de usuario que hereda de la clase TextBox.

    En resumen, que para que puedas ver las nuevas propiedades implementadas en un formulario, tienes que crear un nuevo formulario que herede directamente de aquel donde las has implementado.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    sábado, 21 de mayo de 2016 14:58
    Moderador

Todas las respuestas

  • "James-2016" preguntó:

    > A su vez dichos formularios hacen diversas llamadas a procedimientos que
    > referencian al formulario principal (el que abro en el Sub Main).

    Lo mismo esos formularios NO DEBERÍAN HACER las llamadas a esos procedimientos, o igual esos procedimientos NO DEBERÍAN referenciar al formulario que muestras en el procedimiento Sub Main.

    > Me parece que es asi:
    >
    > Estando en el formulario principal: CualquierFormulario.ShowDialog(me)

    Si no te lo he dicho en otra ocasión anterior, te comento ahora que cuando se muestra un formulario modal (mediante su método ShowDialog) es para que éste NOS DEVUELVA UN VALOR (un color, la ruta de un archivo, un objeto DataRow con los datos del registro seleccionado por el usuario, etc.), no para que éste llame a otros procedimientos que a su vez se encargan de establecer valores en el formulario principal de la aplicación.

    > ¿La consulta es cómo le paso la referencia del formulario principal?

    Para salir del paso, no te va a quedar más remedio que recurrir a pequeñas "triquiñuelas", como por ejemplo, asignarle a la propiedad Tag de un objeto Form la referencia de un formulario existente.

        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    
           ' Queremos mostrar el formulario Form2
            Using frm As New Form2()
                ' A la propiedad Tag le asignamos la referencia del
                ' formulario principal de la aplicación.
                frm.Tag = Module1.GetFormMain()
                frm.ShowDialog()
            End Using
    
        End Sub


    Inserta en algún Module que tengas en tu proyecto la siguiente función:

    Friend Module Module1
    
        Friend Function GetFormMain() As Form
    
            Dim query As List(Of Form) = (From frm As Form In My.Application.OpenForms.Cast(Of Form)
                                          Where frm.Name = "FormMain"
                                          Select frm).ToList()
            If (query.Count > 0) Then
                Return query(0)
            End If
    
            Return Nothing
    
        End Function
    
    End Module


    Observa la siguiente línea:

        ... Where frm.Name = "FormMain"

    Sustituye "FormMain" por el nombre que tenga el formulario principal de tu aplicación.

    Si el formulario que deseas referencias SIEMPRE ESTÁ ABIERTO, puedes hacer uso de la propiedad OpenForms del objeto My.Application.

    Y ahora, en Form2 obtendrías la referencia del formulario consultando el valor de la propiedad Tag:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            ' Referenciamos el formulario existente en el valor
            ' de la propiedad Tag del formulario donde actualmente
            ' se está ejecutando éste código.
            '
            Dim frm As Form = TryCast(Me.Tag, Form)
            If (Not frm Is Nothing) Then
                ' Obtenemos el nombre del formulario.
                MessageBox.Show(frm.Name)
            End If
    
        End Sub

    Pero es lo que te he dicho, que son "triquiñuelas" cuando lo que deberías de hacer es que los formularios modales te devuelvan los valores que deseas obtener de ellos.

    Aunque ya que tienes una función que te devuelve la referencia del formulario principal, para nada te sirve que le asignes un valor a la propiedad Tag, porque desde Form2, o desde cualquier otra parte de tu proyecto, obtendrías la referencia del formulario principal simplemente ejecutando:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            ' Referenciamos el formulario existente en el valor
             ' de la propiedad Tag del formulario donde actualmente
             ' se está ejecutando éste código.
             '
             Dim frm As FormMain = TryCast(Module1.GetFormMain(), FormMain)
             If (Not frm Is Nothing) Then
                 ' Obtenemos el nombre del formulario.
                 MessageBox.Show(frm.Name)
             End If
    
        End Sub

    Te he comentado lo de la propiedad Tag porque ésta nos puede servir a veces para salir del paso de situaciones un tanto "extraordinarias", como parece que es el caso que nos ocupa en ésta ocasión. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    sábado, 21 de mayo de 2016 9:28
    Moderador
  • mm lo que me dice del Tag es una alternativa pero busco la manera "correcta" de hacerlo.

    El formulario lo abro de la forma que muestro abajo, como en otra ocasión me sugirió. En ese caso entiendo que el formulario retorna el resultado del botón presionado, hasta allí me parece que está ok:

    Using forOpcion As New forMiOpcion
       if forOpcion.ShowDialog() <> DialogResult.OK then

          'Aqui continua la ejecución de acuerdo a la respuesta

       end if

    End Using

    Le explico por qué referencio en un procedimiento al menú principal:

    Porque tengo una barra de estado en el menú principal que la voy actualizando de acuerdo a la interacción en cada cuadro de diálogo por tanto necesito referenciar al menú principal desde cada cuadro de diálogo (estos se abren uno a la vez de acuerdo a cada opción del menú principal).

    Por eso consultaba si al agregarle el Me a la llamada del método ShowDialog() le estaba pasando la referencia al Menú Principal al cuadro de diálogo en cuestión y cómo recibirla en este.

    En todo caso, la consulta es ¿Cuál es la manera correcta, recomendada, de hacer lo de arriba?


    • Editado James-2016 sábado, 21 de mayo de 2016 10:35
    sábado, 21 de mayo de 2016 10:34
  • "James-2016" preguntó:

    > En ese caso entiendo que el formulario retorna el resultado del botón presionado.

    El método ShowDialog devuelve un valor DialogResult que nos indica el motivo del cierre de dicho formulario. Pero cuando yo hablaba de devolver un valor, no me refería a un valor DialogResult, más bien a una propiedad pública del formulario que hayamos implementado en el mismo y cuyo valor nos interese conocer, como por ejemplo, la ruta del archivo que el usuario ha escrito en un control TextBox.

    > Por eso consultaba si al agregarle el Me a la llamada del método ShowDialog()
    > le estaba pasando la referencia al Menú Principal al cuadro de diálogo en
    > cuestión y cómo recibirla en este.
    >
    > En todo caso, la consulta es ¿Cuál es la manera correcta, recomendada, de hacer lo de arriba?

    Si a todos los formularios modales los vas a llamar desde el formulario principal de tu aplicación, entonces el asunto tiene fácil solución, porque precisamente tienes que especificar la palabra clave Me para indicar cuál es el formulario propietario del cuadro de diálogo:

         ' Llamamos a un cuadro de diálogo (formulario) cualquiera.
         Using forOpcion As New forMiOpcion()
    
             ' Mostramos el cuadro de diálogo pasándole la referencia del formulario propietario.
             Dim dr As DialogResult = forOpcion.ShowDialog(Me)
        
             If (dr = DialogResult.OK) Then
                ' Ejecutar aquí lo que proceda cuando se haya
    ' pulsado el botón Aceptar.
    Else
    ' Ejecutar aquí lo que proceda cuando se haya
    ' cerrado el cuadro de diálogo haciendo clic
    ' sobre otro botón distinto del botón Aceptar. End If End Using


    Y ahora, en el formulario que actúa de cuadro de diálogo, obtendrías la referencia del formulario propietario leyendo el valor de su propiedad Owner:

     
        ' Referenciamos el formulario propietario,
        ' aquel que ha llamado a forMiOpcion.
        '
        Dim frm As Form = Me.Owner
        MessageBox.Show(frm.Name)

    De ésta manera, ni te hace falta la "triquiñuela" comentada ni tampoco la llamada a la función GetFormMain.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    sábado, 21 de mayo de 2016 11:15
    Moderador
  • ok, mm con Owner obtendría la referencia, gracias, era lo que quería saber.

    -------------------------------------------------------------------------------

    Ya que lo menciona aprovecho para hacerle un par de consultitas:

    -------------------------------------------------------------------------------

    1º Entonces lo que se quiera devolver del formulario se hace a través de propiedades públicas declaradas en el mismo formulario, sería algo así?

    Public Property imaFoto As Image

    y en el cuerpo le asigno a imaFoto la imagen de un PictureBox por ejemplo.

    2º Si declaro propiedades en el formulario estas no aparecen, como en el caso de los controles de usuario, en sus propiedades? (las que se ven al pulsar F4?)


    • Editado James-2016 sábado, 21 de mayo de 2016 11:43
    sábado, 21 de mayo de 2016 11:43
  • "James-2016" preguntó:

    > 1º Entonces lo que se quiera devolver del formulario se hace a través
    > de propiedades públicas declaradas en el mismo formulario, sería algo así?
    >
    > Public Property imaFoto As Image
    >

    Efectivamente. Si no tienes suficiente con las propiedades que implementa la propia clase System.Windows.Forms.Form, de la que heredan por defecto todos aquellos formularios que explícitamente crees desde el IDE de Visual Studio, puedes implementar tantos procedimientos Property que necesites para devolver o asignar los valores concretos que desees.

    > y en el cuerpo le asigno a imaFoto la imagen de un PictureBox por ejemplo.

    Una vez que tengas declarada y creada la instancia de la clase Form correspondiente, desde fuera del formulario podrás asignarle los valores a todas aquellas propiedades cuyo ámbito de visibilidad sea superior a Private:

        Dim frm As New MyForm()
        frm.imaFoto = objetoImage

    > 2º Si declaro propiedades en el formulario estas no aparecen, como en el caso
    > de los controles de usuario, en sus propiedades? (las que se ven al pulsar F4?)

    Si te soy sincero, la verdad es que nunca me he preocupado de esa cuestión, y entiendo que es correcto que no se vean las nuevas propiedades en la Ventana de Propiedades, aunque a aquellas le establezcas los atributos necesarios para que se muestren en dicha ventana, porque para el diseñador de formularios de Visual Studio (que es el que realmente necesita la Ventana de Propiedades para hacer el trabajo que le han encomendado) esas propiedades no existen.

    Debes de tener siempre en cuenta que tu estás utilizando un formulario (una clase) que hereda de otra, por lo que en dicha ventana solamente aparecerán aquellas existentes en la clase base (System.Windows.Forms.Form), que son las únicas que el diseñador de formularios entiende que existen, pero no las nuevas que implementes.

    Estas nuevas propiedades públicas que implementes (por ejemplo, en un formulario llamado MyForm), sí te aparecerán en la Ventana de Propiedades cuando otro formulario que crees herede directamente de MyForm:

    Public Class MyForm
    
        Inherits Form
    
        Private m_image As Image
    
        Public Property MyImage() As Image
            Get
                Return m_image
            End Get
            Set(value As Image)
                m_image = value
            End Set
        End Property
    
    End Class

    Ahora creamos otro formulario que herede de MyForm:

    Public Class MyForm2
    
        Inherits MyForm
    
    End Class

    Y en éste caso, sí te aparecerá la propiedad MyImage en la Ventana de Propiedades, porque el diseñador de formularios ha leído que existe en la clase una propiedad llamada MyImagen con el tipo de dato Image, tal y como muestra la siguiente captura de pantalla:

    Es como si crearas un control de usuario, pero que en lugar de heredar de la clase UserControl heredas de la clase TextBox, por poner un ejemplo. En este caso se mostrarán únicamente las propiedades de la clase TextBox, y aquellas nuevas que implementes en la clase heredada, solamente estarán disponibles en la ventana de Propiedades en aquellos formularios donde hayas insertado tu nuevo control de usuario que hereda de la clase TextBox.

    En resumen, que para que puedas ver las nuevas propiedades implementadas en un formulario, tienes que crear un nuevo formulario que herede directamente de aquel donde las has implementado.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    sábado, 21 de mayo de 2016 14:58
    Moderador
  • mm son detalles que ayudan a comprender mejor cómo funciona esto de las clases, de esa forma que explica en la primera consulta es una forma de inicializar el formulario sin necesidad de cargarlo todo en el evento Load o Shown por ejemplo. Ahora le encuentro sentido también al hecho de por qué es que no aparecen las propiedades de usuario que se crean en un formulario.

    Las valiosas explicaciones proporcionadas ayudan a despejar el panorama, muchas gracias por todo.

    domingo, 22 de mayo de 2016 0:11