Mostrar un formulario sin robar el foco?

Estoy usando un Formulario para mostrar notificaciones (aparece en la parte inferior derecha de la pantalla), pero cuando muestro este formulario, roba el foco del Formulario principal. ¿Hay alguna forma de mostrar este formulario de “notificación” sin robar el foco?

Hmmm, ¿simplemente no está reemplazando a Form.ShowWithoutActivation?

protected override bool ShowWithoutActivation { get { return true; } } 

Y si no desea que el usuario haga clic en esta ventana de notificación tampoco, puede anular CreateParams:

 protected override CreateParams CreateParams { get { CreateParams baseParams = base.CreateParams; const int WS_EX_NOACTIVATE = 0x08000000; const int WS_EX_TOOLWINDOW = 0x00000080; baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW ); return baseParams; } } 

Robado del método ShowWindow de PInvoke.net :

 private const int SW_SHOWNOACTIVATE = 4; private const int HWND_TOPMOST = -1; private const uint SWP_NOACTIVATE = 0x0010; [DllImport("user32.dll", EntryPoint = "SetWindowPos")] static extern bool SetWindowPos( int hWnd, // Window handle int hWndInsertAfter, // Placement-order handle int X, // Horizontal position int Y, // Vertical position int cx, // Width int cy, // Height uint uFlags); // Window positioning flags [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); static void ShowInactiveTopmost(Form frm) { ShowWindow(frm.Handle, SW_SHOWNOACTIVATE); SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST, frm.Left, frm.Top, frm.Width, frm.Height, SWP_NOACTIVATE); } 

(Alex Lyman respondió esto, solo lo estoy expandiendo pegando directamente el código. Alguien con derechos de edición puede copiarlo allí y eliminarlo por lo que a mí respecta;))

Si está dispuesto a usar Win32 P / Invoke , puede usar el método ShowWindow (la primera muestra de código hace exactamente lo que desea).

Hacer esto parece un truco, pero parece funcionar:

 this.TopMost = true; // as a result the form gets thrown to the front this.TopMost = false; // but we don't actually want our form to always be on top 

Editar: Nota, esto simplemente levanta una forma ya creada sin robar el foco.

Esto es lo que funcionó para mí. Proporciona TopMost pero sin robo de foco.

  protected override bool ShowWithoutActivation { get { return true; } } private const int WS_EX_TOPMOST = 0x00000008; protected override CreateParams CreateParams { get { CreateParams createParams = base.CreateParams; createParams.ExStyle |= WS_EX_TOPMOST; return createParams; } } 

Recuerde omitir la configuración de TopMost en el diseñador de Visual Studio o en otro lugar.

Esto es robado, err, prestado, desde aquí (haga clic en Soluciones):

https://connect.microsoft.com/VisualStudio/feedback/details/401311/showwithoutactivation-is-not-supported-with-topmost

El código de muestra de pinvoke.net en las respuestas de Alex Lyman / TheSoftwareJedi hará que la ventana sea una ventana “superior”, lo que significa que no se puede ubicar detrás de las ventanas normales una vez que se ha reventado. Dada la descripción de Matias de para qué quiere usar esto, eso podría ser lo que él quiere. Pero si desea que el usuario pueda colocar su ventana detrás de otras ventanas después de haber aparecido, simplemente use HWND_TOP (0) en lugar de HWND_TOPMOST (-1) en la muestra.

En WPF puedes resolverlo así:

En la ventana, coloca estos atributos:

   

El último atributo es el que necesita ShowActivated = “False”.

Cree e inicie el formulario de notificación en un hilo separado y restaure el foco de regreso a su formulario principal después de que se abra el formulario. Haga que el formulario de notificación proporcione un evento OnFormOpened que se Form.Shown desde el evento Form.Shown . Algo como esto:

 private void StartNotfication() { Thread th = new Thread(new ThreadStart(delegate { NotificationForm frm = new NotificationForm(); frm.OnFormOpen += NotificationOpened; frm.ShowDialog(); })); th.Name = "NotificationForm"; th.Start(); } private void NotificationOpened() { this.Focus(); // Put focus back on the original calling Form } 

También puede mantener un control sobre su objeto NotifcationForm para que pueda ser cerrado programáticamente por el Formulario principal ( frm.Close() ).

Faltan algunos detalles, pero espero que esto te ayude a avanzar en la dirección correcta.

Es posible que desee considerar qué tipo de notificación le gustaría mostrar.

Si es absolutamente crucial informar al usuario sobre algún evento, usar Messagebox.Show sería la forma recomendada, debido a su naturaleza de bloquear cualquier otro evento en la ventana principal, hasta que el usuario lo confirme. Sin embargo, ten en cuenta la ceguera emergente.

Si es menos que crítico, es posible que desee utilizar una forma alternativa para mostrar las notificaciones, como una barra de herramientas en la parte inferior de la ventana. Usted escribió, que muestra las notificaciones en la parte inferior derecha de la pantalla: la forma estándar de hacerlo sería usar un globo con la combinación de un icono de bandeja de sistema .

Tengo algo similar, y simplemente muestro el formulario de notificación y luego hago

 this.Focus(); 

devolver el enfoque a la forma principal.

Esto funciona bien:

 [System.Runtime.InteropServices.DllImport("user32")] public static extern long OpenIcon(long hwnd); [System.Runtime.InteropServices.DllImport("user32")] public static extern long SetForegroundWindow(long hwnd); public static void ActivateInstance() { long MyHndl = 0; long result = 0; Process objProcess = Process.GetCurrentProcess(); MyHndl = objProcess.MainWindowHandle.ToInt32(); result = OpenIcon(MyHndl); // Restore the program. result = SetForegroundWindow(MyHndl); // Activate the application. //System.Environment.Exit(0); // End the current instance of the application. } 

También puedes manejarlo solo por la lógica, aunque tengo que admitir que las sugerencias anteriores donde terminas con un método BringToFront sin robar realmente el foco son las más elegantes.

De todos modos, me encontré con esto y lo resolví utilizando una propiedad DateTime para no permitir más llamadas a BringToFront si las llamadas ya se hicieron recientemente.

Supongamos una clase principal, ‘Core’, que maneja, por ejemplo, tres formularios, ‘Form1, 2 y 3’. Cada formulario necesita una propiedad DateTime y un evento Activate que llame a Core para traer las ventanas al frente:

 internal static DateTime LastBringToFrontTime { get; set; } private void Form1_Activated(object sender, EventArgs e) { var eventTime = DateTime.Now; if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500) Core.BringAllToFront(this); LastBringToFrontTime = eventTime; } 

Y luego crea el trabajo en la clase principal:

 internal static void BringAllToFront(Form inForm) { Form1.BringToFront(); Form2.BringToFront(); Form3.BringToFront(); inForm.Focus(); } 

En una nota lateral, si quiere restaurar una ventana minimizada a su estado original (no maximizada), use:

 inForm.WindowState = FormWindowState.Normal; 

De nuevo, sé que esto es solo una solución parche en la falta de un BringToFrontWithoutFocus. Se entiende como una sugerencia si desea evitar el archivo DLL.

No sé si esto se considera como necro-posting, pero esto es lo que hice, ya que no pude hacerlo funcionar con los métodos “ShowWindow” y “SetWindowPos” de user32. Y no, anulando “ShowWithoutActivation” no funciona en este caso ya que la nueva ventana debe estar siempre en la parte superior. De todos modos, creé un método auxiliar que toma una forma como parámetro; cuando se le llama, muestra la forma, la lleva al frente y la hace TopMost sin robar el foco de la ventana actual (aparentemente lo hace, pero el usuario no se dará cuenta).

  [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern IntPtr SetForegroundWindow(IntPtr hWnd); public static void ShowTopmostNoFocus(Form f) { IntPtr activeWin = GetForegroundWindow(); f.Show(); f.BringToFront(); f.TopMost = true; if (activeWin.ToInt32() > 0) { SetForegroundWindow(activeWin); } } 

Sé que puede sonar estúpido, pero funcionó:

 this.TopMost = true; this.TopMost = false; this.TopMost = true; this.SendToBack(); 

Necesitaba hacer esto con mi ventana TopMost. Implementé el método PInvoke anterior pero descubrí que mi evento Load no se llamaba como Talha anteriormente. Finalmente lo logré. Quizás esto ayudará a alguien. Aquí está mi solución:

  form.Visible = false; form.TopMost = false; ShowWindow(form.Handle, ShowNoActivate); SetWindowPos(form.Handle, HWND_TOPMOST, form.Left, form.Top, form.Width, form.Height, NoActivate); form.Visible = true; //So that Load event happens 

Cuando creas un nuevo formulario usando

 Form f = new Form(); f.ShowDialog(); 

roba el foco porque tu código no puede continuar ejecutándose en el formulario principal hasta que se cierre este formulario.

La excepción es usar threading para crear un formulario nuevo y luego Form.Show (). Sin embargo, asegúrese de que el hilo sea visible globalmente, porque si lo declara dentro de una función, tan pronto como su función finalice, su hilo terminará y la forma desaparecerá.

Lo window.WindowState = WindowState.Minimized; : window.WindowState = WindowState.Minimized; .