2008-10-12 18 views

Respuesta

20

Un cuadro de mensaje es un formulario modal, lo que significa que su ventana primaria está deshabilitada hasta que se descarte el cuadro de mensaje.

Si se llama a una sobrecarga de Show() que no toma un identificador de propietario, entonces un formulario principal generalmente se elige automáticamente. No encuentro nada en la documentación que describa cómo se elige ese formulario, pero mi experiencia es que si el cuadro de mensaje se muestra dentro del hilo de la GUI (es decir, el hilo principal o el hilo de la bomba de mensajes), entonces la ventana activa para ese hilo se elige como el padre.

Otros hilos pueden crear cuadros de mensaje sin formulario primario. Esta podría ser una mala situación, ya que podría situarse detrás de la ventana activa y el usuario ni siquiera sabrá que está allí hasta que cierre el programa. Para evitar esto, puede pasar el control de la ventana principal de la aplicación al método Mostrar, que deshabilitará esa ventana mientras dure el cuadro de mensaje.


añadido: Yo he estado pensando en esto y ahora no estoy tan seguro. El fragmento del reflector que proporcionó a continuación me hace pensar que tal vez el hilo no importe. (¡Dije que no podía encontrar nada en la documentación!)

Tendría que volver y mirar el código para estar seguro, pero creo que los cuadros de mensaje que solía perder detrás de la pantalla principal el formulario puede haber sido en realidad un formulario de mensaje personalizado, en cuyo caso mi experiencia es defectuosa, y nunca tendrá que proporcionar un parámetro de formulario primario.

Disculpa las confusión.

Mi recomendación ahora es que nunca proporcione este parámetro a menos que necesite algo más que la ventana activa para ser el formulario principal.

+0

Gracias. Por lo tanto, parece que solo necesita el uso del parámetro propietario de la ventana si ejecuta Messagebox.Show desde un hilo diferente al de su GUI. – jyoung

+0

Para aclarar aún más: si necesita que su 'MessageBox' sea modal, asegúrese de que se llame desde un' Invoke() 'en el 'Form' al que necesita ser modal. Si encuentra que realmente necesita usar 'Invoke()', asegúrese de pasar también el propietario. (Por lo tanto, por ejemplo, no es necesario especificar 'owner' o' Invoke() 'al llamar' MessageBox.Show() 'en un botón' Click' event handler). – binki

0

si no estoy equivocado, esto impide que la ventana del propietario se enfoque() hasta que se cierre el cuadro de mensaje.

+0

¿Alguien puede citar un ejemplo de una forma en que la ventana del propietario puede recibir el Enfoque() mientras se abre un Cuadro de Mensaje? – jyoung

+0

No. Los cuadros de mensaje siempre son modales, por lo que no puede hacer nada con las ventanas subyacentes. – BlackWasp

+0

@BlackWasp, puede * subir * cualquier ventana que no sea el 'propietario' de 'MessageBox'. – binki

3

Al configurar el propietario, el propietario se desactiva mientras el cuadro de mensaje está abierto.

Si no configura el propietario, el usuario puede hacer clic en otra cosa o incluso cerrar el propietario mientras está abierto el cuadro de mensaje, cuando el cuadro de mensaje se cierra y el código después de la llamada a MessageBox.Show ejecuta su programa puede estar en un estado desconocido, o si el propietario se cerró, ahora está ejecutando código dentro de una ventana que ya no existe y cualquier llamada a métodos de WinForms o WPF (o para ese asunto también WinAPI y cualquier otro marco) es probable que cause un choque.

+0

¿Alguien puede citar un ejemplo de cómo la ventana del propietario puede "el usuario puede hacer clic en otra cosa o incluso cerrar el propietario" mientras se abre un Cuadro de mensaje? – jyoung

+0

Debería leer: ¿Alguien puede citar un ejemplo de una forma en que "el usuario puede hacer clic en otra cosa o incluso cerrar al propietario" mientras se abre un Cuadro de mensaje? – jyoung

+0

En realidad, no puede cerrar el propietario si no especifica el propietario porque entonces no hay un propietario, pero el usuario puede cerrar cualquier ventana de la aplicación en ese momento. Sin embargo, si recuerdo correctamente, MessageBox.Show elige la ventana de primer plano como propietario si no especifica uno. – OregonGhost

0

uso de red de reflector, acabo de encontrar este código en Messagebox.Show:

else if (owner == IntPtr.Zero) 
    owner = UnsafeNativeMethods.GetActiveWindow(); 

Así que si no anidada propiedad (ventana - (propietaria) -> Ventana - (propietaria) -> messageBox), dejando fuera el ownerWindow establece el propietario que normalmente elegiría.

+0

Bueno, no, eso no es verdad; ha descubierto lo que otros ya han dicho, que es que el método asignará al propietario para que sea la ventana activa. Si desea tener absolutamente claro qué ventana está bloqueada mientras el mensaje está activo, debe especificarlo en la llamada al método. – Rob

+0

A menos que desee que otra ventana sea el propietario. Pero tienes razón, nunca configuré al propietario para MessageBox.Show en aplicaciones SWF y nunca vi un comportamiento inesperado. – OregonGhost

+0

A menos que haya un beneficio, "ser absolutamente claro", es algo malo. Hace que leer sea más lento, más propenso a errores y menos fácil de mantener. Así que como un buen programador, siempre busco el beneficio. – jyoung

1

Resulta que la propiedad de la ventana no es transitiva. En el caso donde tiene formulario, generando un formulario, generando un MessageBox, The MessageBox.Show necesita usar el parámetro ownerWindow. El formulario original debe establecerse como la ventana del propietario del MessageBox.

+0

¿Su formulario original llama 'Show()' o 'ShowDialog()' en su forma engendrada? Voy a adivinar 'Show()' porque cuando intento elevar el elemento primario de una forma anidada lanzada a través de 'ShowDialog()' que posee un 'MessageBox', Windows automáticamente levanta el formulario padre, anidado y' MessageBox' y parpadea el 'MessageBox' para mí apropiadamente. – binki

0

La documentación parece implicar que el único propósito del parámetro owner es si especifica MB_HELP, el cuadro de mensaje sabe a qué ventana debe enviar el mensaje WM_HELP.

http://msdn.microsoft.com/en-us/library/ms645505%28VS.85%29.aspx


Oh, sólo se dio cuenta de la OP estaba a punto .net - Le di una respuesta acerca de winapi - lo siento!

1

Según las pruebas y this other answer, .net elegirá automáticamente la ventana actualmente enfocada en el mismo hilo que su llamada MessageBox.Show(). Para obtener el comportamiento correcto, debe asegúrese de mostrar el MessageBox del mismo hilo que esta ventana y especifique la ventana con la que el MessageBox está lógicamente asociado como owner. Un MessageBox solo modalmente bloquea la entrada a otros Form s en la secuencia desde la que se inicia. Esto probablemente se relaciona con la forma en que MessageBox se hace modal (¿tal vez intercepta los mensajes dirigidos al hilo actual y solo permite algunos mensajes a través de ventanas que no sean ella misma?). El efecto de la entrada de bloqueo modal es que el usuario no podrá enfocar estas ventanas o cualquier control dentro de ellas e intentar hacerlo produce el sonido "Ding". Además, si no se especifica el propietario, el MessageBox seleccionará automáticamente la ventana activa en el hilo actual. Si la ventana actualmente activa proviene de un hilo diferente (¡o de una aplicación diferente!), El MessageBox no tendrá propietario. Eso significa que obtiene su propia entrada en la barra de tareas: se comporta como su propia ventana distintiva. El usuario puede subir otras ventanas en su aplicación (incluso si el usuario no puede interactuar con ellas). Puede obtener la situación en la que su programa deja de responder a la entrada del usuario con el usuario confundido porque el usuario de alguna manera levantó la ventana principal de la aplicación después de que se mostrara el cuadro de diálogo. Sin embargo, si el propietario está configurado correctamente, al tratar de levantar la ventana principal, el MessageBox se levantará y parpadeará.

Para que todo esto funcione bien con las ventanas hijas, asegúrese de que cada ventana hija tenga su conjunto de propiedades Owner. Esto sucederá automáticamente si llama al ShowDialog() (que hace que su modal Form personalizado (y haga pase su parámetro owner en los mismos casos donde pasaría owner al MessageBox.Show())).

Ahora, la mayoría de las formas de codificación de win consiste en escribir el código directamente en los controladores de eventos dentro de una subclase Form. Al escribir manejadores de eventos winforms, puede asumir muchas cosas. En primer lugar, nunca debe tener una llamada al this.Invoke() como una declaración de nivel superior en un controlador de eventos GUI porque dichos controladores son siempre ejecutados en el mismo subproceso que se creó la subclase Form. En segundo lugar, para muchos (pero no todos) de estos controladores, puede suponer que el Form tiene el foco (y sería así elegido automáticamente por MessageBox.Show() como su propietario). Por ejemplo, al escribir código dentro del controlador de evento Click de un botón (posiblemente llamado button1_Click), puede suponer con seguridad que el formulario está enfocado (porque llamar al PerformClick() en el formulario Button es una mala práctica). Sin embargo, un Timer.Tick puede suceder incluso cuando su formulario no está enfocado. Entonces, en el caso de Timer.Tick, existe no need to Invoke() (just like any other winforms event handler) pero existe es una necesidad de especificar owner. Este último caso es más difícil de notar porque el desarrollador debe tener su aplicación desenfocada para darse cuenta de que un diálogo que se muestra en este caso se comporta de forma ligeramente diferente a cuando se enfoca su aplicación.Por lo tanto, especifique owner siempre que necesite usar Invoke()o si es posible que el evento se active cuando la ventana no está enfocada. Esta guía se aplica al llamar al MessageBox.Show() y Form.ShowDialog().

La mayor parte de lo que discuto aquí es el resultado de messing around mientras lee las otras respuestas.

1

Calling MessageBox.Show(frmMain,"a message","a title") añade la forma TextDialog a la colección Application.OpenForms() formas de la aplicación, a lo largo del lado forman la frmMain principal en sí. Permanece después de cerrar el Messagebox.

Acabo de descubrir 14 de estos cuando llamé a btnOK_Click() y establecí un punto de interrupción.

Cuando llamé al frmMain.Close() para cerrar el formulario principal, no pasó nada. frmMain no se cerrará hasta que los 14 Application.OpenForms también estén cerrados o, de lo contrario, debe llamar al Application.Exit().

Cuestiones relacionadas