2009-06-12 15 views
19

Amigos,cómo mostrar formulario frente en C#

Por favor, ¿alguien sabe cómo mostrar un formulario desde una aplicación de otro modo invisible, y han que conseguir el enfoque (es decir, aparecen en la parte superior de otras ventanas)? Estoy trabajando en C# .NET 3.5.

sospecho que he tomado "totalmente errónea" ... hago noApplication.Run (nueva ElFormulario()) en lugar de eso(nueva ElFormulario()). ShowModal(). .. El formulario es básicamente un diálogo modal, con algunas casillas de verificación; un cuadro de texto, y botones Aceptar y Cancelar. El usuario marca una casilla de verificación y escribe una descripción (o lo que sea) luego presiona OK, el formulario desaparece y el proceso lee la entrada del usuario desde el Formulario, lo descarta y continúa el proceso.

Esto funciona, excepto cuando el formulario muestra que no se enfoca, sino que aparece detrás de la aplicación "host", hasta que hace clic en la barra de tareas (o lo que sea). Este es un comportamiento muy molesto, que predigo que causará muchas "llamadas de soporte", y la versión VB6 existente no tiene este problema, por lo que retrocederé en usabilidad ... y los usuarios no aceptarán eso (y ni deberían hacerlo).

Así que ... Estoy empezando a pensar que necesito volver a pensar todo el shebang ... Debo mostrar el formulario por adelantado, como una "aplicación normal" y adjuntar el resto del proceso al botón Aceptar -click evento. Debería funcionar, pero tomará un tiempo que no tengo (ya estoy a tiempo/presupuesto) ... así que primero tengo que tratar de hacer que el enfoque actual funcione ... incluso con rapidez y métodos sucios

Entonces, ¿alguien sabe cómo "forzar" un formulario .NET 3.5 (por medios justos o aves de corral) para obtener el enfoque? Estoy pensando en llamadas a la API de Windows "mágicas" (lo sé

Twilight Zone: Esto solo parece ser un problema en el trabajo, estamos usando Visual Studio 2008 en Windows XP SP3 ... I Simplemente no reproduje el problema con un SSCCE (ver a continuación) en casa en Visual C# 2008 en Vista Ulimate ... Esto funciona bien. ¿Eh? WTF?

Además, juraría que ayer en el trabajo se mostró el formulario cuando ejecuté el EXE, pero no cuando F5'ed (o Ctrl-F5'ed) directamente desde el IDE (que acabo de soportar) ... En casa, el formulario muestra bien en ambos sentidos. Totalmente confuso!

Puede o no ser relevante, pero Visual Studi o se estrelló y quemó esta mañana cuando el proyecto se estaba ejecutando en modo de depuración y editando el código "sobre la marcha" ... se quedó atascado lo que supuse era un ciclo interminable de mensajes de error. El mensaje de error era algo sobre "no puedo depurar este proyecto porque no es el proyecto actual, o algo así ... Así que lo acabo de matar con el explorador de procesos. Comenzó de nuevo bien, e incluso se ofreció a recuperar el" perdido "archivo, una oferta que acepté

using System; 
using System.Windows.Forms; 

namespace ShowFormOnTop { 
    static class Program { 
     [STAThread] 
     static void Main() { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      //Application.Run(new Form1()); 
      Form1 frm = new Form1(); 
      frm.ShowDialog(); 
     } 
    } 
} 

Antecedentes:. estoy portar una aplicación de VB6 a .NET existente ... es un 'plugin' para una 'aplicación SIG cliente' llamada MapInfo El. el cliente existente "funcionó de manera invisible" y mis instrucciones son "mantener la nueva versión lo más cerca posible de la versión anterior", que funciona bastante bien (después de años de parcheo); está escrita en un lenguaje no compatible, por lo que necesitamos

Sobre mí: Soy bastante novato en C# y .NET en general, aunque tengo un certificado de limpieza de fondos, he sido programador profesional durante 10 años; Entonces, como que "sé algunas cosas".

Cualquier idea sería muy bienvenida ... y gracias a todos por tomarse el tiempo para leer hasta aquí. La consistencia no es (aparentemente) mi fuerte.

Saludos. Keith.

Respuesta

44

Simplemente

yourForm.TopMost = true; 
+0

voy a ir a darle una nudos. Gracias por su sugerencia. Lo aprecio – corlettk

+0

Simplemente estableciendo this.TopMost = true en Form_Load funciona como un amuleto. ¡Gracias, gracias, y gracias! – corlettk

+0

Tuve un problema similar, y había intentado usar esto. Enfocar() y esto. Activar() en el evento Load sin éxito, pero estableciendo esto.TopMost = true en el evento Load funcionó perfectamente para mí. Gran publicación, y muchas gracias por la respuesta. +1 – Jim

4

Hay una sobrecarga de Form.ShowDialog() que toma un objeto IWin32Window. Esa IWin32Window se trata como la ventana principal para el formulario.

Si tiene la ventana principal como System.Windows.Forms.Form, continúe y simplemente páselo. De lo contrario, obtenga el HWND (tal vez mediante P/Invocar a FindWindow()) y cree una implementación ficticia de IWin32Window que simplemente devuelva el HWND (More details).

+0

No hay otras ventanas en la aplicación ... solo este "pequeño diálogo" (para permitir al usuario ingresar algunos metadatos para la actualización). – corlettk

3
  1. Dijiste que funciona bien cuando usas Application.Run. ¿Por qué no quieres usar Application.Run, entonces?
  2. ¿Ha intentado llamar al BringToFront() desde OnLoad o OnShown?
+0

Dije que no estoy usando Application.Run, no dije que hace que el formulario sea visible. No "ejecuté" la aplicación porque esto no es fundamentalmente un "evento controlado"; es una línea principal bastante larga que solo necesita mostrar un diálogo modal con algunos controles ... Si necesito reestructurar la aplicación para que sea "impulsada por eventos" entonces lo haré ... No lo hice inicialmente porque no se adapta al problema PRIMERO, espero encontrar otra solución para el formulario que se muestra "detrás" de la aplicación SIG de host. Probaré BringToFront() en el método OnShow (que son nuevos para mí ;-) Agradezco tu ayuda. Aclamaciones. Keith. – corlettk

+1

Lo siento, imaginé que habías dicho que Application.Run evitaba el problema. Sin embargo, tu objeción es un poco extraña. Los formularios reciben eventos de la misma manera ya sea que haga Application.Run o Form.ShowDialog. De hecho, la forma en que estos dos trabajan es casi (pero no del todo) idéntica. Ambos terminan llamando a ThreadContext.FromCurrent(). RunMessageLoop (ThreadContext es una clase interna dentro de System.Windows.Forms.dll). –

+0

Ajá ... Mis objeciones a Application.Run se basan en la ignorancia pura y sin trabas. Me acabo de dar cuenta de que Application.Run BLOQUEA EL HILO QUE LLAMA. (Perdonen mis gritos, no hay muchas opciones para enfatizar en los comentarios de SO). Realmente aprecio su consejo, y esta mañana voy a trabajar para probarlo. Lo siento si era un poco narky, era tarde y estaba muy cansado, y cada vez más frustrado. – corlettk

0

Parece que el comportamiento es específico de XP ... Por lo tanto, no puedo reproducirlo en Vista.

http://www.gamedev.net/community/forums/topic.asp?topic_id=218484

EDIT: PD: Es más allá de mi hora de dormir (02 a.m. ;-).

Gracias a todos por sus respuestas ... hay algunas "cosas" que puedo intentar ... incluso podría ir a la oficina mañana para probarlas ... Sí, sí ... Una vez tuve una vida, pero lo cambié por un corte de pelo y un trabajo ;-)

Saludos a todos. Keith.

+0

Yo votaría esta (mi) respuesta si pudiera ... Acabo de terminar de "verificar totalmente" que: form.TopMost = true; arregla el problema en XP (todas nuestras versiones actuales + siguientes de SOE) y Vista. Dando aún más crédito a la afirmación de que "¡Yo soy @ Putz!" ... Algunos días simplemente no puedes tomar un truco ;-) – corlettk

+1

Puedes borrar esta respuesta si quieres :) –

1

Lo he pirateado desde una aplicación en la que he estado trabajando. Tenemos una gran aplicación que carga una serie de módulos escritos por diferentes equipos. Hemos escrito uno de estos módulos, y necesitamos tener un diálogo de inicio de sesión abierto durante esta inicialización. Se estableció en '.TopMost = true', pero eso no funcionó.

Utiliza WindowsFormsSynchronizationContext para abrir un cuadro de diálogo, y luego obtener el resultado del cuadro de diálogo de nuevo.

Raramente hago codificación de GUI, y sospecho que esto puede ser excesivo, pero podría ayudar a alguien si se atasca. Tuve problemas para entender cómo se pasa el estado a SendOrPostCallback, ya que todos los ejemplos que pude encontrar no lo usaron.

También esto se toma de una aplicación en funcionamiento, pero he eliminado varios bits de código y he cambiado algunos de los detalles. Disculpas si no compila.

public bool Dummy() 
{ 

// create the login dialog 
DummyDialogForm myDialog = new DummyDialogForm(); 

// How we show it depends on where we are. We might be in the main thread, or in a background thread 
// (There may be better ways of doing this??) 
if (SynchronizationContext.Current == null) 
{ 
    // We are in the main thread. Just display the dialog 
    DialogResult result = myDialog.ShowDialog(); 
    return result == DialogResult.OK; 
} 
else 
{ 
    // Get the window handle of the main window of the calling process 
    IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle; 

    if (windowHandle == IntPtr.Zero) 
    { 
     // No window displayed yet 
     DialogResult result = myDialog.ShowDialog(); 
     return result == DialogResult.OK; 
    } 
    else 
    { 
     // Parent window exists on separate thread 
     // We want the dialog box to appear in front of the main window in the calling program 
     // We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread 
     object resultState = null; 
     WindowsFormsSynchronizationContext.Current.Send(
      new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState); 

     if (resultState is DialogResult) 
     { 
      DialogResult result = (DialogResult) resultState; 
      return result == DialogResult.OK; 
     } 
     else 
      return false; 

    } 
} 

}

3

Form.Activate() funcionó en mi caso.

1

Activate() funcionó para mí también.

BringToFront() no hicieron nada en este caso, no sé por qué.

-1

Esto es lo que uso para llevar un formulario abierto que es parte de mi aplicación al frente. Incluso puede usarlo con un botón. Pero el formulario debe estar abierto o la aplicación se romperá.

"YourOpenForm" tiene que ser el nombre de su formulario desde la ventana de propiedades.

private void button1_Click(object sender, EventArgs e) 
    { 
     Application.OpenForms["YourOpenForm"].BringToFront(); 
    } 

¡Buena suerte!

2

Ésta es la solución final que escribí después de 20 intentos diferentes:

/* A workaround for showing a form on the foreground and with focus, 
* even if it is run by a process other than the main one 
*/ 
public static void ShowInForeground(this Form form, bool showDialog = false) 
{ 
    if (showDialog) 
    { 
     //it's an hack, thanks to http://stackoverflow.com/a/1463479/505893 
     form.WindowState = FormWindowState.Minimized; 
     form.Shown += delegate(Object sender, EventArgs e) { 
      ((Form)sender).WindowState = FormWindowState.Normal; 
     }; 
     form.ShowDialog(); 
    } 
    else 
    { 
     //it's an hack, thanks to http://stackoverflow.com/a/11941579/505893 
     form.WindowState = FormWindowState.Minimized; 
     form.Show(); 
     form.WindowState = FormWindowState.Normal; 

     //set focus on the first control 
     form.SelectNextControl(form.ActiveControl, true, true, true, true); 
    } 
} 
Cuestiones relacionadas