2009-04-08 28 views
7

Tengo un comportamiento muy extraño que solo parece suceder en un formulario.Cerrar un formulario desde el controlador de carga

Básicamente estoy creando una instancia de Form, y llamando al Show() para mostrar el formulario sin bloqueo. En el controlador de eventos Load de ese formulario, tengo alguna lógica que puede llamar al this.Close() bajo ciertas circunstancias. Esto cierra el formulario, pero luego el método Show() en el código del cliente arroja un ObjectDisposedException.

El seguimiento de la pila de la ObjectDisposedException es el siguiente:

en System.Windows.Forms.Control.CreateHandle()
en System.Windows.Forms.Form.CreateHandle()
en Sistema .Windows.Forms.Control.get_Handle()
en System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
en System.Windows.Forms.Form.SetVisibleCore (valor booleano)
en System.Windows.Forms.Control .Mostrar()
... etc.

Esto es lo que estoy viendo esto suceda:

  1. Control.Show() se llama
  2. se puso en marcha mi forma
  3. la OnFormLoad método se llama
  4. el manejador FormLoad evento se llama, en el interior del cual llamo this.Close()
  5. el método OnFormClosing es ca llena
  6. el manejador FormClosing evento se llama
  7. Dispose se llama en mi formulario y controla todo lo que es el usuario

y luego en algún lugar hacia el final del método Control.Show(), se trata de obtener un identificador para el formulario , que se asusta y arroja una excepción porque el objeto está marcado como desechado.

Mi verdadera pregunta es, ¿por qué puedo hacer exactamente lo mismo en cualquier otra forma que tenga sin excepciones? ¿Es un problema de GC? Intenté poner una llamada GC.Collect() justo después del this.Close() y no hace ninguna diferencia. Como dije, sucede el 100% del tiempo en este formulario, y nunca en ningún otro lado, independientemente de los controles de usuario secundarios, el alcance de la variable de formulario, etc.

¿Alguna idea?

Respuesta

7

Sé que esto es una cuestión de edad, pero nadie parecía haber publicado la respuesta obvoius.

Usted dice que llama Control.Show() y luego Form.Close() y luego se elimina el formulario. Bueno, a menos que use MDI o use ShowDialog, tal como está documentado. Sin embargo, la versión corta de la documentación Close() es "Cierra el formulario", en realidad también lo elimina implícitamente bajo ciertas condiciones.

vea la sección Notas: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

Si desea mostrar un nuevo formulario. Use el método Hide() en lugar de Close().

Espero que ayude a otras almas en busca.

Y muchachos, no dejen de buscar "No sé por qué funciona a veces". Eso se convierte en un software defectuoso con muchas herramientas defensivas "Llamaré a este método de nuevo por si acaso". No está bien.

+0

Desafortunadamente, no utilizo Windows Dev, pero parece correcto. ¡Gracias! – LoveMeSomeCode

+0

No funciona en .Net2.0 – Vadim

0

Me parece, sin mirar de cerca, que la forma más limpia de lograr lo que desea puede ser hacer una clase de formulario personalizado que deriva de Form, y anular OnFormLoad(...) y/o Show() para comprobar su estado y cancelar salir temprano

Dicho esto, no sé por qué funcionaría a veces y no en otras ocasiones.

+0

en realidad, ese es el caso aquí. No lo mencioné b/c todos mis formularios son de esa manera. La forma base anula OnFormLoad y OnFormClose, pero solo hace cosas de registro en esos métodos. La secuencia de llamadas es la misma en todas las formas. – LoveMeSomeCode

1

Una posibilidad:

Pueden tener un temporizador en este formulario, que está siendo inicializado y activado en su caso FormLoad. También se debe deshabilitar y detener el temporizador antes de cerrar el formulario, si el temporizador intenta acceder al formulario cuando se dispara.

que he visto formas antes de que hacen esto ...

+0

buena idea, pero no hay temporizadores en este formulario. varios controles de usuario, pero revisé para asegurarme de que se están llamando a todos sus métodos de eliminación. – LoveMeSomeCode

3

En caso de carga no es realmente buena idea cerrar el formulario. Hazlo después del evento Activado.

0

Ha intentado entrar en el código .NET para ver qué línea de código que se está llamando cuando la excepción se está produciendo? Si tiene VS 2008, puede hacerlo yendo a Herramientas -> Opciones -> Depuración y seleccionando Habilitar el Acceso a la Fuente del Marco .NET. Tenga cuidado, puede llevar un tiempo descargar todos los archivos necesarios, pero de esta manera puede entrar en el formulario. Muestre() y vea exactamente lo que está sucediendo.

+0

no, ojalá. Estoy usando VS 2005. Sin embargo, miré el reflector, y es como dice la pila de llamadas: justo al final del Control. Muestra que llama a FocusActiveControlInternal, que llama al getter Handle, que arroja la excepción si se elimina. – LoveMeSomeCode

5

Ok, el odio a responder a mi propia pregunta, pero esto era yo volviendo loco, y fue uno de los errores más difíciles de reproducir que he visto nunca.

En mi formulario anulo los métodos OnFormLoad y OnFormClose, donde guardo/restauro el tamaño, la ubicación y el estado de ventana del formulario a/desde el registro. Saqué este código y solucionó el problema. Lo extraño es que lo devolví y el problema no volvió.

finalmente se reproduce el problema: hay que dejar que la forma se abre completamente, maximizar, y luego ciérrela de modo que el estado maximizado se guarda en el registro. Luego, cuando lo abra de nuevo, lo establecerá en Maximizado, y si se cierra en el controlador de carga, intenta acceder al Tamaño/Ubicación cuando se está cerrando. Aparentemente, el acceso a estos valores en el método OnFormClosing provoca que el formulario trate de enfocarse IF Y SOLO SI el formulario está maximizado, lo que es ilegal, ya que el formulario se ha eliminado.

Así que, básicamente, no se puede acceder a las propiedades de presentación de formulario en el método OnFormClosing de un formulario, si esa forma se va a llamar Cerca de él es el evento Load. (A menos que comprueba la Dispuesta apuntalar primero)

bastante pedazo de sabiduría de Winforms que conozco, pero lo escribo de todos modos.

0

Ok, resulta que es un poco más simple y más genérica de lo que pensaba, pero todavía raro y oscuro.

Si está guardando/cargando el formulario Tamaño/Ubicación/WindowState cuando el formulario se carga/cierra como lo hacemos, debe asegurarse de que el método OnLoad llame a base.OnLoad primero para que el controlador de evento Form Load se dispare , y ENTONCES establecer las propiedades. Si no lo haces, solo se generará un problema si el formulario llama a Close desde dentro del método Load. Obtendrá una ObjectDisposedException en la llamada Mostrar después de que se haya completado el evento de cierre del formulario.

Me duele la cabeza.

0

Form.Shown() Es el truco también.

22

La mejor manera de hacerlo:

this.BeginInvoke(new MethodInvoker(this.Close)); 

esta es la manera más simple que usted no conseguirá ObjectDisposedException

+1

Funciona bien en .Net2.0 – Vadim

3

Si desea cerrar un formulario como si el usuario pulsa la cruz en la parte superior derecha esquina (generalmente significa cancelar), simplemente agregue el siguiente código.

this.DialogResult = System.Windows.Forms.DialogResult.Cancel; 
this.Close(); 

Esto también funciona en la función de carga del formulario:

private void MyForm_Load (object sender, EventArgs e) 
{ 
    // do some initializations 

    if (!ContinueLoadingForm()) 
    { 
     this.DialogResult = System.Windows.Forms.DialogResult.Cancel; 
     this.Close(); 
     return; 
    } 
    // continue loading the form 
} 

Si no desea que el formulario sea visible por un corto tiempo, establezca la propiedad Visible falsa (por ejemplo, en el diseñador o constructor), y establecerlo en verdadero cuando esté seguro de que el programa puede seguir cargando.

+0

Parece que no puede evitar el formulario que se muestra por el momento. –

0

Según tengo entendido, establecer DialogResult del formulario cerrará el formulario, puede que tenga que ser distinto de DialogResult.None. (es decir, no es necesario que llame al método Form.Close()).

El problema también es, en parte, que si en algún otro lugar del código está accediendo a una propiedad del formulario o control que contiene, puede impedir que se cierre el formulario.

También puede ser mejor si, como se ha sugerido, usted tiene una propiedad, p.

private bool _loadedOk = false; 

en el formulario que establezca en el código de inicialización. En uno de los eventos posteriores después de Form_Loaded, lo interroga y cierra el formulario si es falso.

Tal vez alguien pueda sugerir el mejor evento para hacer esto en ??

Cuestiones relacionadas