none
Falla programa al cerrar formulario No Modal, cuando lo abro desde uno Modal RRS feed

  • Pregunta

  • Muy buenos días a todos;

    Mi problema es el siguiente:

    1. En el evento click de la barra de herramientas abro en forma modal un formulario:

        Private Sub TSM_UNESTRATO_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TSM_UNESTRATO.Click, TSM_UNESTRATO_MENU.Click
    
            'Hace visible el botón BUT_ACEPTARUNESTRATO,del Form FRM_SUELO1.
            FRM_SUELO1.BUT_ACEPTARUNESTRATO.Visible = True
            'Oculta el botón BUT_ACEPTARESTRATO1 del Form FRM_SUELO1.
            FRM_SUELO1.BUT_ACEPTARESTRATO1.Visible = False
            'Muestra en forma modal el formulario FRM_SUELO1.
            FRM_MODULOES_1.Modulo_Es(1)
            '
            'Muestro el formulario.
            FRM_SUELO1.ShowDialog()
            '
        End Sub

    2. Dentro de dicho formulario mediante la combinación de teclas Crl+Enter, abro un formulario en forma No Modal, de la siguiente forma:

        Private Sub FRM_SUELO1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
    
            Try
                'Verifico que ha tecleado la combinación de teclas Ctrl+Enter.
                If e.KeyData = (Keys.Control + Keys.Enter) Then
    
                    'No lo muestro en la barra de herramientas.
                    FRM_CONVERTIDOR_UNIDADES.ShowInTaskbar = False
                    'Indico que el propietario es el formulario actual, con el fin de que se muestre siempre, y pueda interactuar
                    'con ambos formularios al mismo tiempo.
                    FRM_CONVERTIDOR_UNIDADES.Show(Me)
                    '
                End If
                '
            Catch ex As Exception
    
            End Try
    
        End Sub

    3. Cuando cierro el formulario No Modal con el Button X de su ControlBox , es donde me falla el código pues se salta a la línea del punto 1, específicamente en la línea de código :

            'Muestro el formulario.
            FRM_SUELO1.ShowDialog()
            '

    Mostrándome el siguiente error:

    Entiendo, que tiene que ver algo con el identificador del formulario, pero la verdad no he podido resolverlo. Dicho formulario No Modal llamado:

     FRM_CONVERTIDOR_UNIDADES

    ..., lo abro desde muchos formularios No Modales que uso en mi aplicación. ¿Cuál sería la solución?.

    Muchas gracias, espero me puedan colaborar.

    Dios le bendiga.



    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970


    sábado, 19 de agosto de 2017 16:03

Respuestas

  • "Harold Quintero Pineda" escribió:

    > Ayer le dedique tiempo depurando la aplicación, y el error me saltaba en el Designer
    > del formulario, especialmente en este código(es el método Dispose que implementa
    > automático el diseñador);

    Harold, si eso fuera así, NOS SALTARÍA EL ERROR A TODOS, pero afortunadamente el método Dispose que genera automáticamente Visual Studio cuando añadimos un nuevo formulario al proyecto, NO GENERA ERROR ALGUNO. Lo que tienes que hacer es DETECTAR qué línea de tu código es la que hace que se ejecute el método Dispose del formulario, que normalmente se ejecutará cuando se cierre el formulario, y tras ejecutarse sus eventos FormClosing y FormClosed, lo que hará que por último se desencadene su evento Disposed. Por supuesto, si no se han implementado ninguno de los eventos mencionados, no se desencadenará evento alguno, claro está.

    ¿Has contado el número de veces que se ejecuta ese método Dispose? Te lo pregunto porque si se ejecuta más de una vez, eso es indicio de que implícita o explícitamente se está llamando mediante código a dicho método. Por una casualidad de la vida, ¿no habrás sobrescrito el método Finalize? Es decir, no habrás incluido en ese formulario el siguiente método:

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Te comento que una llamada explícita al método MyBase.Finalize hará que implícitamente se ejecute el método Dispose del formulario (primera vez), el cual también se ejecutará cuando se cierre el formulario (segunda vez), lo que puede dar lugar a resultados inesperados. No será tu caso, pero he visto peores cosas. ;-)

    > Mi solución(no se si es la más técnica), fue cambiar el MyBase.Dispose() por MyBase.Hide(),
    > y funcionó correctamente en toda mi aplicación. Esto sólo me pasa cuando muestro el
    > formulario en forma No Modal(Show).
    >
    > ¿Que opina usted señor Montejo?. Como le dije, cuando depuraba me fuí a la línea de código
    > que causaba el error, y era precisamente esa, y cambiando al .Hide() funcionó, no entiendo
    > muy bien, pues el Dispose  siempre se implementa en el Designer automáticamente, y nunca me
    > había pasado algo así.

    ¿Que qué opino? Que como "chapuza" para salir del paso y evitar el error está bien, pero desde luego no voy a ser yo el que te aconseje cambiar la llamada al método Dispose por ocultar el formulario, que es lo que hace el método Hide. Visualmente hablando es como si "cerraras el formulario" (nótense las comillas dobles), porque éste desaparece de la vista, pero el formulario continua estando en memoria, así como los componentes y datos que existan en el mismo, ya que estos desaparecerán (se destruirán) cuando explícitamente se cierre el formulario, o implícitamente cuando finalice la aplicación.

    Insisto que algo mal tienes en ese formulario, pero desde luego, el culpable no es su método Dispose. Este podrá ser el desencadenante, el que hace que se ejecute el código que modifica una colección, porque el mensaje de error de la InvalidOperationException que estás teniendo no puede ser más claro: Colección modificada. ¿Qué colección se modifica? Pues por motivos obvios lo ignoro por completo.

    Edito: Como comentas que el error lo desencadena el método MyBase.Dispose(), me viene a la mente preguntarte si en ese formulario existe algún control de usuario diseñado por ti o por algún tercero que no sean los controles clásicos que aparecen en el Cuadro de Herramientas.

    Te lo comento porque el método MyBase.Dispose() del formulario hará que se ejecute el método Dispose del control de usuario, y habrá que ver lo que se ejecuta en el mismo, porque igual le estamos echando la culpa del error al formulario (el desencadenante) y la excepción realmente se produce en el código que existe en el control de usuario (el culpable). ;-)


    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.



    domingo, 20 de agosto de 2017 15:04
    Moderador

Todas las respuestas

  • "Harold Quintero Pineda" escribió:
    >
    > 3. Cuando cierro el formulario No Modal con el Button X de su ControlBox ,
    > es donde me falla el código pues se salta a la línea del punto 1,
    > específicamente en la línea de código :
    >
    >  'Muestro el formulario.
    >  FRM_SUELO1.ShowDialog()
    >  '
    > Mostrándome el siguiente error:
    >
    > Excepción no controlada
    >
    > System.InvalidOperationException: 'Colección modificada: puede
    > que no se ejecute la operación de enumeración.'
    >
    > Entiendo, que tiene que ver algo con el identificador del formulario, pero la verdad
    > no he podido resolverlo. Dicho formulario No Modal llamado:
    > FRM_CONVERTIDOR_UNIDADES

    Hola, Harold:

    Me parece a mí que el error que estás obteniendo (InvalidOperationException) poco tiene que ver con el identificador del formulario, más bien con alguna colección que se ha modificado en alguna parte del formulario, o de alguna clase o módulo del proyecto.

    Te salta a la línea del punto 1 porque como se indica en el mensaje de error, NO HAS CONTROLADO la excepción en el procedimiento donde realmente se ha producido aquella, por lo que la excepción se propaga hasta llegar a la línea del código donde ha comenzado la llamada al método donde realmente se ha producido el error.

    Como comentas que el error se produce cuando deseas cerrar "el formulario No Modal con el Button X de su ControlBox", lo único que te puedo decir es que establezcas un punto de interrupción al comienzo de los eventos FormClosing o FormClosed, si es que lo tienes implementados, claro está. Y si no es el caso, entonces vas a tener que establecer el punto de interrupción en la línea donde muestras el formulario:

        FRM_SUELO1.ShowDialog()

    y recorrer todo el código pulsando la tecla F8 hasta que llegues a la línea donde se produce el error.

    > ..., lo abro desde muchos formularios No Modales que uso en mi aplicación. ¿Cuál sería la solución?.

    La verdad es que tienes un "papelón bueno" hasta que des con la línea de código que produce la excepción del tipo InvalidOperationException, que por el mensaje de error que se muestra, alguna colección se ha tenido que modificar en algún bucle del tipo For Each ... Next, Do ... Loop o While ... End While.

    Esos "dolores de cabeza y pérdida de tiempo" es lo que suele ocurrir por no encerrar el código susceptible de producir una excepción entre su correspondiente bloque Try ... Catch... End Try, para capturar la misma y actuar en consecuencia. ;-)

    >    FRM_SUELO1.ShowDialog()

    Por cierto, ¿FRM_SUELO1 qué es? ¿El nombre del formulario? En lugar de utilizar la variable que crea Visual Basic para acceder fácilmente al formulario, tal y como se hacía con Visual Basic clásico, ¿por qué no te olvidas de ello y creas e instancias la correspondiente variable objeto que referencie al formulario que deseas abrir?

        Using frm As New FRM_SUELO1()
            ' Mostramos el formulario modal
            frm.ShowDialog()
        End Using

    Si vas a abrir un formulario NO MODAL, no vayas a encerrar la declaración e instancia del formulario entre un bloque Using ... End Using, porque cuando se ejecute este último se destruirá el formulario:

        Dim frm As New FRM_CONVERTIDOR_UNIDADES()
    
        ' Mostramos el formulario no modal
        frm.Show(Me)
    

    Lo mismo hasta te resulta de utilidad la lectura del siguiente artículo:

    Abrir y cerrar formularios con Visual Basic .net

    Un saludo


    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, 19 de agosto de 2017 18:44
    Moderador
  • Buenas tardes señor Montejo;

    Gracias de antemano por su respuesta. Pues e comento que no tengo ningún bucle. El FRM_SUELO1, si corresponde al formulario MODAL desde donde llamo por medio de la combianción de teclas CTR+Enter al formulario FRM_CONVERTIDOR_UNIDADES, por medio del método Show(no modal). Intenté llamando al FRM_SUELO1 con un Using, lo mimso para el caso del No Modal con una nueva instancia(sin el uso del Using).

    En el formulario no modal no tengo implementado código en el FormClosed ni en el Closing; hice una interrupción en dicho formulario FRM_CONVERTIDOR_UNIDADES(que es quine me causa el error al cerrarlo), pero de inmediato salta al error que le he mencionado a la línea del código de FRM_SUELO1.ShowDialog.

    Tengo un desespero terrible, pues la única solución que encontré es llamando al FRM_CONVERTIDOR_UNIDADES, también de forma MODAL, pero esa no es a idea de mi aplicación.





    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970

    sábado, 19 de agosto de 2017 20:24
  • "Harold Quintero Pineda" escribió:

    > Tengo un desespero terrible, pues la única solución que encontré es llamando
    > al FRM_CONVERTIDOR_UNIDADES,  también de forma MODAL, pero esa no es a idea
    > de mi aplicación.

    Comprendo tu desesperación, pero compréndeme también a mí cuando escribo que es IMPOSIBLE averiguar los motivos de la InvalidOperationException sin conocer el código completo de tu aplicación, al menos todo aquel código que se ejecuta desde que muestras el formulario hasta que se cierra, porque como creo que bien podrás comprender, no aparece una excepción por el simple hecho de cerrar "el formulario No Modal con el Button X de su ControlBox", porque si así fuera, hacía tiempo que no hubiésemos dedicado a otras tareas menos problemáticas, al menos el que está escribiendo este mensaje. ;-)

    > En el formulario no modal no tengo implementado código en el FormClosed ni en el Closing;

    Si tu lo dices me lo creo, pero igual has instalado un controlador para el evento FormClosing mediante la instrucción AddHandler, que para el caso es lo mismo.

    ¿Por casualidad estás recorriendo en alguna parte de tu proyecto la colección de formularios actualmente abiertos mediante un bucle For Each ... Next? Te voy a poner un ejemplo para reproducir la excepción InvalidadOperationException que estás obteniendo cuando intentas cerrar el formulario NO MODAL abierto.

    Imagina que abres el formulario NO MODAL de la siguiente manera:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            ' Instalamos el controlador para el evento FormOnClosing
            ' del formulario FRM_CONVERTIDOR_UNIDADES.
            '
            AddHandler Form1.FormClosing, AddressOf FormOnClosing
                
            ' Mostramos el formulario de manera NO MODAL.
            FRM_CONVERTIDOR_UNIDADES.Show(Me)
    
        End Sub

    Inserta en el formulario donde muestras el formulario no modal el siguiente controlador de evento:

        Private Sub FormOnClosing(sender As Object, e As FormClosingEventArgs)
    
            ' Recorrer la colección de formularios actualmente abiertos.
            For Each f As Form In Application.OpenForms
                ' Destruir el formulario; esto hará que
    ' internamente se modifique la colección. f.Dispose()
    Next End Sub

    Cuando desees cerrar el formulario FRM_CONVERTIDOR_UNIDADES abierto de manera no modal se ejecutará el código existente en el procedimiento FormOnClosing, y como dentro del bucle estamos destruyendo el formulario referenciado, esto hará que cuando se ejecute la instrucción Next se produzca la misma InvalidOperationException que estás obteniendo, tal y como muestra la siguiente captura de pantalla:


    No quiere decir que estés ejecutando el mismo código que aparece en el ejemplo indicado, pero éste muestra como se puede generar una InvalidOperationException cuando se modifica una colección (en este caso, la de formularios abiertos) dentro de un bucle For Each ... Next, porque lo que hace el bucle internamente es iterar a través de los índices de una colección, y como ésta se ha modificado al destruir el formulario, ¡zas! ¡Excepción al canto! ¡Así de sencillo! ;-)

    Si no estás recorriendo la colección de formularios abiertos, lo mismo estás recorriendo otro tipo de colección diferente, pero una excepción como la que estás obteniendo, no aparece de la noche a la mañana ni por arte de magia, por tanto, tendrás que depurar tu aplicación hasta que des con el causante de la excepción; otra cosa no te puedo decir. Ya me gustaría a mí decirte en qué línea del código se produce la excepción, pero todavía no ejerzo de "adivino". ;-)


    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.


    domingo, 20 de agosto de 2017 6:56
    Moderador
  • Muy buenos días Señor Montejo;

    Agradezco por transmitir su conocimiento, y ser tan didáctico.

    Ayer le dedique tiempo depurando la aplicación, y el error me saltaba en el Designer del formulario, especialmente en este código(es el método Dispose que implementa automático el diseñador);

    <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
    Partial Class FRM_CONVERTIDOR_UNIDADES
        Inherits System.Windows.Forms.Form
    
        'Form reemplaza a Dispose para limpiar la lista de componentes.
        <System.Diagnostics.DebuggerNonUserCode()> _
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing AndAlso components IsNot Nothing Then
                    components.Dispose()
                End If
            Finally
                MyBase.Dispose()
            End Try
        End Sub

    El error se daba en el MyBase.Dispose(); no sé porque motivo, pues todos los formularios los implementan automáticamente. Mi solución(no se si es la más técnica), fue cambiar el MyBase.Dispose() por MyBase.Hide(), y funcionó correctamente en toda mi aplicación. Esto sólo me pasa cuando muestro el formulario en forma No Modal(Show).

    ¿Que opina usted señor Montejo?. Como le dije, cuando depuraba me fuí a la línea de código que causaba el error, y era precisamente esa, y cambiando al .Hide() funcionó, no entiendo muy bien, pues el Dispose siempre se implementa en el Designer automáticamente, y nunca me había pasado algo así.


    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970


    domingo, 20 de agosto de 2017 14:29
  • "Harold Quintero Pineda" escribió:

    > Ayer le dedique tiempo depurando la aplicación, y el error me saltaba en el Designer
    > del formulario, especialmente en este código(es el método Dispose que implementa
    > automático el diseñador);

    Harold, si eso fuera así, NOS SALTARÍA EL ERROR A TODOS, pero afortunadamente el método Dispose que genera automáticamente Visual Studio cuando añadimos un nuevo formulario al proyecto, NO GENERA ERROR ALGUNO. Lo que tienes que hacer es DETECTAR qué línea de tu código es la que hace que se ejecute el método Dispose del formulario, que normalmente se ejecutará cuando se cierre el formulario, y tras ejecutarse sus eventos FormClosing y FormClosed, lo que hará que por último se desencadene su evento Disposed. Por supuesto, si no se han implementado ninguno de los eventos mencionados, no se desencadenará evento alguno, claro está.

    ¿Has contado el número de veces que se ejecuta ese método Dispose? Te lo pregunto porque si se ejecuta más de una vez, eso es indicio de que implícita o explícitamente se está llamando mediante código a dicho método. Por una casualidad de la vida, ¿no habrás sobrescrito el método Finalize? Es decir, no habrás incluido en ese formulario el siguiente método:

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub

    Te comento que una llamada explícita al método MyBase.Finalize hará que implícitamente se ejecute el método Dispose del formulario (primera vez), el cual también se ejecutará cuando se cierre el formulario (segunda vez), lo que puede dar lugar a resultados inesperados. No será tu caso, pero he visto peores cosas. ;-)

    > Mi solución(no se si es la más técnica), fue cambiar el MyBase.Dispose() por MyBase.Hide(),
    > y funcionó correctamente en toda mi aplicación. Esto sólo me pasa cuando muestro el
    > formulario en forma No Modal(Show).
    >
    > ¿Que opina usted señor Montejo?. Como le dije, cuando depuraba me fuí a la línea de código
    > que causaba el error, y era precisamente esa, y cambiando al .Hide() funcionó, no entiendo
    > muy bien, pues el Dispose  siempre se implementa en el Designer automáticamente, y nunca me
    > había pasado algo así.

    ¿Que qué opino? Que como "chapuza" para salir del paso y evitar el error está bien, pero desde luego no voy a ser yo el que te aconseje cambiar la llamada al método Dispose por ocultar el formulario, que es lo que hace el método Hide. Visualmente hablando es como si "cerraras el formulario" (nótense las comillas dobles), porque éste desaparece de la vista, pero el formulario continua estando en memoria, así como los componentes y datos que existan en el mismo, ya que estos desaparecerán (se destruirán) cuando explícitamente se cierre el formulario, o implícitamente cuando finalice la aplicación.

    Insisto que algo mal tienes en ese formulario, pero desde luego, el culpable no es su método Dispose. Este podrá ser el desencadenante, el que hace que se ejecute el código que modifica una colección, porque el mensaje de error de la InvalidOperationException que estás teniendo no puede ser más claro: Colección modificada. ¿Qué colección se modifica? Pues por motivos obvios lo ignoro por completo.

    Edito: Como comentas que el error lo desencadena el método MyBase.Dispose(), me viene a la mente preguntarte si en ese formulario existe algún control de usuario diseñado por ti o por algún tercero que no sean los controles clásicos que aparecen en el Cuadro de Herramientas.

    Te lo comento porque el método MyBase.Dispose() del formulario hará que se ejecute el método Dispose del control de usuario, y habrá que ver lo que se ejecuta en el mismo, porque igual le estamos echando la culpa del error al formulario (el desencadenante) y la excepción realmente se produce en el código que existe en el control de usuario (el culpable). ;-)


    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.



    domingo, 20 de agosto de 2017 15:04
    Moderador
  • Hola de nuevo señor Montejo;

    De verdad busqué y busqué la solución correcta;  por ningún lado tengo incluido ni el Me.Close(), ni Me.Finalize(), para este formulario. Es primera vez que me pasa esto, y no me gusta tener soluciones rebuscadas de código, pero lamentablemente para mi caso la del Me.Hide(), es la que por ahora me funciona.

    Agradezco mucho por su colaboración.

    Dios me lo bendiga.


    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970

    domingo, 20 de agosto de 2017 16:16