2010-06-29 14 views
30

Descripción del problemaWPF aplicación pierde por completo el foco en la ventana estrecha

Si hago una ventana no modal como una ventana secundaria a través de establecer que el dueño de la ventana para una ventana padre, y luego mostrar un cuadro de mensaje desde dentro esta ventana secundaria, la ventana principal perderá foco si cierro la ventana secundaria. Si Windows Explorer u otra aplicación está abierta, esta aplicación obtendrá el foco y mi ventana principal estará oculta.

Esto parece ser un problema conocido, ya que lo vi en otro newsgroups, pero no he visto una buena solución. Establecer al propietario como nulo en OnDeactivate no es una opción. Configurar el propietario antes de mostrar MessageBox para anular y restablecer después de eso no ayuda. Establecer que el propietario anule en el evento OnClosed tampoco ayuda.

solución simple que se encuentra

Si experimenta el mismo problema que he descrito, coloque el código siguiente en el OnClosing de todas las ventanas secundarias.

void OnClosing(System.ComponentModel.CancelEventArgs e) 
    base.OnClosing(e); 
    if (null != Owner) { 
     Owner.Activate(); 
    } 
    // .... 

Se puede seguir con cualquier otra lógica de procesamiento, incluso se tolera la apertura de MessageBoxes.

Ejemplo de código

La cuestión parece ser mucho más grande como pensaba. El siguiente ejemplo eliminará el foco de la ventana principal si se abrirá el cuadro de mensaje y se cerrará la ventana secundaria (Copie el código en un controlador de eventos cargado de una Ventana).

Window firstChildWindow = new Window() { 
    Title = "Floating Window", Width = 100, Height = 70 
}; 
firstChildWindow.Owner = Window.GetWindow(this); 

Button button = new Button() { Content="MessageBox"}; 
button.Click += delegate { 
    MessageBox.Show("Klicking her breaks the focus-chain."); }; 
firstChildWindow.Content = button; 
firstChildWindow.Show(); 

También este ejemplo se rompe la cadena de enfoque:

Window firstChildWindow = new Window() { 
    Title = "Floating Window", Width = 100, Height = 70 
}; 
firstChildWindow.Owner = Window.GetWindow(this); 
firstChildWindow.Show(); 

Window secondChildWindow = new Window() { 
    Title="Second Window",Width=100,Height=70}; 
secondChildWindow.Content = new TextBlock() { 
    Text="SecondWindow"}; 
secondChildWindow.Owner = firstChildWindow; 
secondChildWindow.Show(); 

tiene a alguien una solución para este problema. Pienso en un truco para desencadenar dando enfoque al padre después del cierre, con Dispatcher o DispachterTimer o quizás sería trabajo forzar manualmente el foco al padre en el cerrado, pero todo esto me parece muy sucio (y también es un poco complicado si hay ventanas de propiedad más activa del mismo padre, como tengo en mi aplicación actual).

¿Nadie conoce una solución clara para esto?

Recursos

MSDN Description (véase el recuadro de comentarios para las ventanas no modales abiertos llamando Mostrar())

Same problem on msdn forums without appropriate solution

Por favor, véase también: Instable focus of WPF apps

+0

He entendido mal su pregunta, lo siento, he borrado mi respuesta. – Nir

+0

No hay problema, gracias por la respuesta de todos modos. Cambié la descripción para explicar mi problema un poco más claro :) – HCL

Respuesta

22

Lo más probable es que tenga dos ventanas independientes de nivel superior y cerró una de ellas. Esto a veces provocará que el foco salte a otra aplicación.

Esto también ocurre si un windows posee un segundo, que a su vez posee un tercero. Probable ERROR en la API de Win32 pero ha estado con nosotros para siempre, así que buena suerte para solucionarlo.

La solución alternativa es volver a enfocar manualmente el elemento en el evento Closing del nieto. Pero en este caso, nieto es un mensaje para que no puedas hacer eso. Lo más fácil de hacer es tener un messagebox para parent. El siguiente más fácil es hacer su propio control de cuadro de mensaje.

+0

El segundo párrafo describe exactamente mi problema. ¿Tienes más información sobre esto? – HCL

+0

No, desafortunadamente, no. Me encontré con el error al escribir código Win32 hace mucho tiempo. La única solución fue procesar WM_CLOSE y devolver SetFocus() al propietario de la ventana. En WinForms, WM_CLOSE se traduce en ϞFormClosing, y hay un método Focus() en la clase Form. Debe haber algo similar para WPF. – Joshua

+2

¿Cómo llegó eso? :) http://en.wiktionary.org/wiki/%CF%9E – porges

0

es posible escribir su propio cuadro de mensaje, puede implementarlo como un flotador, deshabilitar toda la pantalla cuando se muestra.

comprueba la muestra del marco de calibración de mvvm, hay una buena implementación de messagebox como servicio.

0

La propiedad no tiene nada que ver con la activación de la ventana. Para ver esto, cambie el propietario de la segunda ventana a la ventana superior y ejecute el programa. Observe que nada cambia. La propiedad tiene que ver con "Si se minimiza una ventana, se deben minimizar otras ventanas". Por lo tanto, tiene que usar el código de activación personalizado.

19

Esto es un error muy molesto, la solución más común, siempre es:

llamada Me.Owner.Focus en caso Window_Unloaded o Window_Closing.

Pero eso todavía no funciona al 100%, todavía se ve la ventana de fondo parpadeando en primer plano (muy brevemente), antes de que el foco se restaure correctamente.

He encontrado un método que funciona mejor:

llamada Me.Owner.Activate antes Me.Close (o en el caso _Closing).

+0

Parece que tendré que hacer esto. Voy a ponerlo en un comportamiento reutilizable, así que todos mis puntos de vista pueden usar esto para una buena medida. Solo como una nota al margen, parece que tengo este problema con un escenario diferente a los dos que menciona OP. – Andy

+0

También utilicé Owner.Focus() además de Owner.Activate(); de lo contrario, mis atajos de teclado no funcionaban de inmediato. – scottheckel

2

Quizás estoy bastante retrasado en el asunto.
@HCL este problema podría resolverse más fácilmente estableciendo el opciones parámetro de la MessageBox.show() a MessageBoxOptions.None.

Saludos ...

0

de Johsua .activate (véase más arriba) solución funciona muy bien con todo tipo de tipos de ventana. Al menos me funcionó.

0

tuve un problema similar. Tenía una ventana principal, donde las ventanas secundarias restantes se asignaban a esa ventana a través de la propiedad Propietario. Si la ventana principal tenía dos o más hijos, después de cerrar el segundo hijo, la aplicación pierde el foco. Usé truco con child.Owner = null antes de cerrar, pero luego mi ventana secundaria siguiente pierde el foco. Lo manejé al obtener todos los hijos y establecer el foco en el último antes de cerrar al niño. Aquí está el ejemplo de código:

private void OnClosing(object sender, CancelEventArgs cancelEventArgs) 
     { 
      var childWindows = (sender as Window).Owner.OwnedWindows; 
      if (childWindows.Count - 2 >= 0) 
       childWindows[childWindows.Count - 2].Focus(); 
      else 
      { 
       (sender as Window).Owner.Focus(); 
      } 
      (sender as Window).Owner = null; 
     } 
Cuestiones relacionadas