c# - siempre - form en primer plano
¿Cómo hacer que una ventana siempre se mantenga arriba en.Net? (12)
Tengo una aplicación C # winforms que ejecuta una macro en otro programa. El otro programa mostrará continuamente ventanas y, en general, hará que las cosas parezcan locas, a falta de una palabra mejor. Quiero implementar un botón de cancelación que evitará que el proceso se ejecute, pero parece que no puedo obtener la ventana para mantenerme en la cima. ¿Cómo hago esto en C #?
Editar: He intentado TopMost = verdadero; , pero el otro programa sigue mostrando sus propias ventanas por encima. ¿Hay alguna manera de enviar mi ventana a la cima cada milisegundos?
Editar: La forma en que resolví esto fue agregando un icono de la bandeja del sistema que cancelará el proceso haciendo doble clic en él. El icono de la bandeja del sistema no se tapa. Gracias a todos los que respondieron. Leí el artículo sobre por qué no hay una ventana ''súper en la parte superior'' ... lógicamente no funciona.
¿Cuál es la otra aplicación que está tratando de suprimir la visibilidad de? ¿Has investigado otras formas de lograr el efecto deseado? Por favor, hazlo antes de someter a tus usuarios a un comportamiento deshonesto como el que estás describiendo: lo que estás tratando de hacer suena más bien como lo que hacen ciertos sitios traviesos con las ventanas del navegador ...
Al menos intenta adherirte a la regla de Least Surprise . Los usuarios esperan poder determinar el orden z de la mayoría de las aplicaciones. No sabes qué es lo más importante para ellos, por lo que si cambias algo, debes enfocarte en empujar la otra aplicación detrás de todo en lugar de promover la tuya.
Esto es, por supuesto, más complicado, ya que Windows no tiene un administrador de ventanas particularmente sofisticado. Dos enfoques se sugieren a sí mismos:
- enumerar ventanas de nivel superior y verificar a qué proceso pertenecen , dejando caer su orden z si es así . (No estoy seguro de si hay métodos de marco para estas funciones de WinAPI).
- Jugando con los permisos del proceso hijo para evitar que acceda al escritorio ... pero no intentaría esto hasta que fallara el otro enfoque, ya que el proceso secundario podría terminar en un estado zombie y requerir la interacción del usuario.
¿Por qué no hacer que su formulario sea un cuadro de diálogo?
myForm.ShowDialog();
Aquí está el equivalente de SetForegroundWindow:
form.Activate();
He visto gente haciendo cosas raras como:
this.TopMost = true;
this.Focus();
this.BringToFront();
this.TopMost = false;
http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html
El siguiente código hace que la ventana siempre permanezca en la parte superior y la haga sin marco.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace StayOnTop
{
public partial class Form1 : Form
{
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public Form1()
{
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
TopMost = true;
}
private void Form1_Load(object sender, EventArgs e)
{
SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
}
protected override void WndProc(ref Message m)
{
const int RESIZE_HANDLE_SIZE = 10;
switch (m.Msg)
{
case 0x0084/*NCHITTEST*/ :
base.WndProc(ref m);
if ((int)m.Result == 0x01/*HTCLIENT*/)
{
Point screenPoint = new Point(m.LParam.ToInt32());
Point clientPoint = this.PointToClient(screenPoint);
if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)12/*HTTOP*/ ;
else
m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
}
else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)10/*HTLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)2/*HTCAPTION*/ ;
else
m.Result = (IntPtr)11/*HTRIGHT*/ ;
}
else
{
if (clientPoint.X <= RESIZE_HANDLE_SIZE)
m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
m.Result = (IntPtr)15/*HTBOTTOM*/ ;
else
m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
}
}
return;
}
base.WndProc(ref m);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= 0x20000; // <--- use 0x20000
return cp;
}
}
}
}
Estaba buscando hacer que mi aplicación WinForms "Siempre en la parte superior", pero establecer "TopMost" no hizo nada por mí. Sabía que era posible porque WinAmp hace esto (junto con una serie de otras aplicaciones).
Lo que hice fue hacer una llamada a "user32.dll". No tuve ningún reparo en hacerlo y funciona muy bien. Es una opción, de todos modos.
Primero, importe el siguiente espacio de nombre:
using System.Runtime.InteropServices;
Agregue algunas variables a su declaración de clase:
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
Agregar prototipo para la función user32.dll:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
Luego en su código (agregué la llamada en Form_Load ()), agregue la llamada:
SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
Espero que ayude. Reference
Establecer Form.TopMost
Establezca la propiedad .TopMost
del .TopMost
en verdadero.
Probablemente no quiera dejarlo así todo el tiempo: configúrelo cuando su proceso externo comience y vuelva a colocarlo cuando termine.
La forma en que resolví esto fue creando un icono de bandeja del sistema que tenía una opción cancelar.
Sé que esto es viejo, pero no vi esta respuesta.
En la ventana (xaml) agrega:
Deactivated="Window_Deactivated"
En el código detrás de Window_Deactivated:
private void Window_Deactivated(object sender, EventArgs e)
{
Window window = (Window)sender;
window.Activate();
}
Esto mantendrá su ventana en la parte superior.
Si al "enloquecer" te refieres a que cada ventana sigue robando el foco del otro, TopMost no resolverá el problema.
En cambio, intente:
CalledForm.Owner = CallerForm;
CalledForm.Show();
Esto mostrará la forma ''infantil'' sin que robe el foco. El formulario hijo también se mantendrá en la parte superior de su padre incluso si el padre está activado o centrado. Este código solo funciona fácilmente si ha creado una instancia del formulario secundario desde el formulario de propietario. De lo contrario, es posible que deba configurar al propietario utilizando la API.
Tuve un lapso momentáneo de 5 minutos y olvidé especificar el formulario completo como este:
myformName.ActiveForm.TopMost = true;
¡Pero lo que realmente quería era ESTO!
this.TopMost = true;
Form.TopMost
funcionará a menos que el otro programa esté creando ventanas superiores.
No hay forma de crear una ventana que no esté cubierta por nuevas ventanas superiores de otro proceso. Raymond Chen explained por qué.