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 manera de mostrar este formulario de "notificación" sin robar el foco?

Author: Peter Mortensen, 2008-10-01

17 answers

Hmmm, no es simplemente sobreescribir la Forma.¿Espectáculo sin actividad suficiente?

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

Y si tampoco desea que el usuario haga clic en esta ventana de notificación, 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;
  }
}
 153
Author: Martin Plante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-29 12:29:25

Robado de PInvoke.net's ShowWindow método:

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 borrar esto por lo que me importa;))

 65
Author: TheSoftwareJedi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 12:45:48

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

 14
Author: Alex Lyman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 12:37:03

Esto es lo que funcionó para mí. Proporciona lo más alto pero sin robar el enfoque.

    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 superior en Visual Studio designer o en cualquier otro lugar.

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

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

 10
Author: RenniePet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-09 14:09:12

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 plantea una forma ya creada sin robar el foco.

 9
Author: Matthew Scharley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 03:20:25

El código de ejemplo de pinvoke.net en las respuestas de Alex Lyman/TheSoftwareJedi hará que la ventana sea una ventana "superior", lo que significa que no puedes colocarla detrás de las ventanas normales después de que aparezca. Dada la descripción de Matías de para qué quiere usar esto, eso podría ser lo que quiere. Pero si desea que el usuario pueda poner su ventana detrás de otras ventanas después de que la haya abierto, simplemente use HWND_TOP (0) en lugar de HWND_TOPMOST (-1) en la muestra.

 8
Author: Micah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 04:44:40

En WPF puedes resolverlo así:

En la ventana ponga estos atributos:

<Window
    x:Class="myApplication.winNotification"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Notification Popup" Width="300" SizeToContent="Height"
  WindowStyle="None" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" Topmost="True" Focusable="False" ShowActivated="False" >
</Window>

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

 6
Author: Ziketo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-20 23:36:21

Crea e inicia el Formulario de notificación en un subproceso separado y restablece el foco a tu formulario principal después de que se abra el Formulario. Haga que el formulario de notificación proporcione un evento OnFormOpened que se dispara 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 identificador para su objeto NotifcationForm para que pueda ser cerrado programáticamente por el formulario principal (frm.Close()).

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

 3
Author: Bob Nadler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 03:24:46

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

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

Si es menos que crítico, es posible que desee utilizar una forma alternativa de mostrar notificaciones, como una barra de herramientas en la parte inferior de la ventana. Usted escribió, que se muestran las notificaciones en la parte inferior derecha de la pantalla - la forma estándar de hacer esto sería utilizar un globo punta con la combinación de un bandeja del sistema icono.

 3
Author: Silver Dragon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 12:39:09

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

this.Focus();

Para volver a centrar la atención en la forma principal.

 2
Author: pkr298,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 22:25:29

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.

}
 2
Author: Factor Mystic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-25 04:25:49

Usted puede manejarlo solo por lógica también, aunque tengo que admitir que las sugerencias anteriores donde terminas con un método BringToFront sin robar el enfoque es el más elegante.

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

Supongamos una clase core, 'Core', que maneja por ejemplo tres formas, 'Form1, 2 y 3'. Cada formulario necesita una propiedad DateTime y un evento Activate que llama a Core para traer windows 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 crear el trabajo en la Clase Core:

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

En una nota al margen, si desea restaurar una ventana minimizada a su estado original (no maximizada), utilice:

inForm.WindowState = FormWindowState.Normal;

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

 2
Author: Meta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 13:28:30

No se si esto es considerado como necro-posting, pero esto es lo que hice ya que no pude conseguirlo trabajando con los métodos "ShowWindow" y "SetWindowPos" de user32. Y no, sobreescribir "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 helper que toma un formulario como parámetro; cuando se llama, muestra el formulario, lo lleva al frente y lo hace más alto 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);
        }
    }
 1
Author: domi1819,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-03 06:54:36

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

this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
 0
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-07 11:14:27

Necesitaba hacer esto con mi ventana más alta. Implementé el método PInvoke anterior, pero descubrí que mi evento de carga no estaba siendo llamado como Talha anterior. Finalmente lo logré. Tal vez esto ayude 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
 0
Author: Steven Cvetko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-10 23:38:08

Cuando se crea un nuevo formulario usando

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

Roba el foco porque su código no puede continuar ejecutándose en el formulario principal hasta que este formulario esté cerrado.

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

 -3
Author: Fry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 03:26:43

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

 -4
Author: Pawel Pawlowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-09 18:06:58