Tengo algunos problemas para que un cuadro de notificación se comporte correctamente en C#. Básicamente estoy mostrando una forma sin boar en la parte inferior derecha de la pantalla, que muestra un mensaje durante unos segundos y luego desaparece. El problema es que necesito que aparezca encima de otras ventanas sin que sea capaz de robar el foco. Idealmente, quiero que sea un código puramente administrado, aunque al mirar ejemplos similares dudo que esto sea posible.Ventana de notificación: evitar que la ventana se vuelva a enfocar
En este momento estoy evitando que el robo del foco cuando se llama a Form.Show() con una anulación:
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
get { return true; }
}
y luego haciendo caso omiso de clics del ratón con:
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);
}
Sin embargo me parece que si los utilizo junto con TopMost = true (que necesito), gana foco de todos modos, y si todas las demás ventanas se minimizan, también gana foco.
Entonces, ¿hay alguna forma de evitar que un formulario se vuelva enfocado (ya sea con un clic del mouse, alt-tab, etc.), mientras sigue siendo el top/top superior? Incluso el solo hecho de enfocarse de inmediato en la ventana desde la que se lo robó funcionaría (aunque introduciría el parpadeo).
Cualquier sugerencia sería muy apreciada, realmente estoy atrapado en esto.
EDIT:
Ok, así que finalmente me las arreglé para conseguir este trabajo usando:
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
get { return true; }
}
// and
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams param = base.CreateParams;
param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
return param;
}
}
// and
[DllImport("user32.dll")]
private extern static IntPtr SetActiveWindow(IntPtr handle);
private const int WM_ACTIVATE = 6;
private const int WA_INACTIVE = 0;
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOUSEACTIVATE)
{
m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
return;
}
if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
{
if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
{
if (m.LParam != IntPtr.Zero)
{
SetActiveWindow(m.LParam);
}
else
{
// Could not find sender, just in-activate it.
SetActiveWindow(IntPtr.Zero);
}
}
}
También he añadido Form.Hide() para el evento GotFocus de manera que incluso si de alguna manera obtener un enfoque , simplemente se cierra y se sale de la forma de los usuarios lo antes posible.
Además, si alguien se pregunta, las constantes para todos los estilos de ventana, etc. se pueden encontrar en WINUSER.H, está en línea en http://www.woodmann.com/fravia/sources/WINUSER.H si no puede encontrarlo.
Sin embargo, si alguien puede ver una forma más elegante de hacerlo, se lo agradecería.
Gracias, esto es perfecto para evitar que se enfoque, ni siquiera aparece en alt-tab ahora, que es increíble. El único problema menor que todavía tengo es que el TopMost = true parece anular ShowWithoutActivation, por lo que aún gana foco cuando se llama a form.Show(). ¿Hay alguna forma de evitar esto? – yebetrollin
Vea la respuesta de Ziketo para eso. También recuerde votar las preguntas de las personas que ayudaron. –