Respuestas:
Hmmm, ¿no es simplemente anular Form.ShowWithoutActivation lo 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;
}
}
form1.Enabled = false
para evitar que los controles internos se robaran el foco
WS_EX_NOACTIVATE
y WS_EX_TOOLWINDOW
son 0x08000000
y 0x00000080
respectivamente.
Robados 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 eliminarlo por lo que me importa;))
Si está dispuesto a usar Win32 P / Invoke , puede usar el método ShowWindow (el primer ejemplo de código hace exactamente lo que desea).
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):
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: Tenga en cuenta que esto simplemente genera un formulario ya creado sin robar foco.
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 puede colocarla detrás de las ventanas normales después de que aparezca. Dada la descripción de Matias de para qué quiere usar esto, eso podría ser lo que quiere. Pero si desea que el usuario pueda colocar su ventana detrás de otras ventanas después de que la haya desplegado, simplemente use HWND_TOP (0) en lugar de HWND_TOPMOST (-1) en la muestra.
En WPF puedes resolverlo así:
En la ventana pon 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".
Cree e inicie el Formulario de notificación en un hilo separado y restablezca el enfoque 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 desencadena desde el Form.Shown
evento. 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 de su objeto NotifcationForm para que el formulario principal ( frm.Close()
) pueda cerrarlo mediante programación .
Faltan algunos detalles, pero espero que esto te lleve en la dirección correcta.
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, usar Messagebox.Show sería la forma recomendada, debido a su naturaleza, para bloquear cualquier otro evento en 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. Escribió que muestra las notificaciones en la esquina inferior derecha de la pantalla; la forma estándar de hacerlo sería utilizando una punta de globo con la combinación de un icono de la bandeja del sistema .
Esto funciona bien
Ver: OpenIcon - MSDN y SetForegroundWindow - MSDN
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public static void ActivateInstance()
{
IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
// Restore the program.
bool result = OpenIcon(hWnd);
// Activate the application.
result = SetForegroundWindow(hWnd);
// End the current instance of the application.
//System.Environment.Exit(0);
}
También puede manejarlo solo por lógica, aunque tengo que admitir que las sugerencias anteriores donde termina con un método BringToFront sin realmente robar el foco es la 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.
Suponga una clase principal, 'Core', que maneja, por ejemplo, tres formas, 'Form1, 2 y 3'. Cada formulario necesita una propiedad DateTime y un evento Activate que llame a Core para traer 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 Core Class:
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), use:
inForm.WindowState = FormWindowState.Normal;
Una vez más, sé que esto es solo una solución de parche en ausencia de un BringToFrontWithoutFocus. Es una sugerencia si desea evitar el archivo DLL.
No sé si esto se considera como publicación necro, pero esto es lo que hice, ya que no pude hacerlo funcionar con los métodos "ShowWindow" y "SetWindowPos" de user32. Y no, anular "ShowWithoutActivation" no funciona en este caso ya que la nueva ventana debe estar siempre arriba. De todos modos, creé un método auxiliar que toma una forma como parámetro; cuando se le llama, muestra el formulario, lo lleva al frente y lo convierte en TopMost sin robar el foco de la ventana actual (aparentemente lo hace, pero el usuario no lo notará).
[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 esto 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 arriba. Finalmente lo logré. Quizás 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
Cuando 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 se cierre este formulario.
La excepción es mediante el uso de subprocesos para crear un nuevo formulario 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 salga, su hilo terminará y el formulario desaparecerá.
Figurado a cabo: window.WindowState = WindowState.Minimized;
.