.net - sirve - no puedo cambiar de ventana con alt tab
¿La mejor manera de ocultar una ventana desde el selector de programa Alt-Tab? (13)
Actualizar:
Según @donovan, los días modernos WPF lo admite de forma nativa, mediante la configuración de ShowInTaskbar="False"
y Visibility="Hidden"
en el XAML. (No he probado esto todavía, pero sin embargo decidí cambiar la visibilidad del comentario)
Respuesta original:
Hay dos formas de ocultar una ventana del selector de tareas en Win32 API:
- para agregar el estilo de ventana extendida
WS_EX_TOOLWINDOW
, ese es el enfoque correcto. - para que sea una ventana secundaria de otra ventana.
Desafortunadamente, WPF no admite un control tan flexible sobre el estilo de ventana como Win32, por lo tanto, una ventana con WindowStyle=ToolWindow
termina con los WS_CAPTION
predeterminados WS_CAPTION
y WS_SYSMENU
, lo que hace que tenga un título y un botón de cerrar. Por otro lado, puede eliminar estos dos estilos configurando WindowStyle=None
, pero eso no configurará el estilo extendido WS_EX_TOOLWINDOW
y la ventana no se WS_EX_TOOLWINDOW
del selector de tareas.
Para tener una ventana de WPF con WindowStyle=None
que también está oculta desde el selector de tareas, puede hacerlo de dos maneras:
- vaya con el código de ejemplo anterior y convierta la ventana en una ventana secundaria de una pequeña ventana de herramientas ocultas
- modifique el estilo de la ventana para incluir también el estilo extendido
WS_EX_TOOLWINDOW
.
Yo personalmente prefiero el segundo enfoque. Por otra parte, hago algunas cosas avanzadas como extender el cristal en el área del cliente y permitir que WPF dibuje el título de todos modos, así que un poco de interoperabilidad no es un gran problema.
Aquí está el código de muestra para el enfoque de solución de interoperabilidad de Win32. Primero, la parte XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300"
ShowInTaskbar="False" WindowStyle="None"
Loaded="Window_Loaded" >
No hay nada demasiado elegante aquí, solo declaramos una ventana con WindowStyle=None
y ShowInTaskbar=False
. También agregamos un controlador al evento Loaded donde modificaremos el estilo de ventana extendida. No podemos hacer ese trabajo en el constructor, ya que todavía no hay ningún identificador de ventana. El controlador de eventos en sí es muy simple:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper wndHelper = new WindowInteropHelper(this);
int exStyle = (int)GetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE);
exStyle |= (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW;
SetWindowLong(wndHelper.Handle, (int)GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
}
Y las declaraciones de interoperabilidad Win32. Eliminé todos los estilos innecesarios de las enumeraciones, solo para mantener el código de muestra aquí pequeño. Además, desafortunadamente el punto de entrada SetWindowLongPtr
no se encuentra en user32.dll en Windows XP, de ahí el truco de enrutar la llamada a través de SetWindowLong
.
#region Window styles
[Flags]
public enum ExtendedWindowStyles
{
// ...
WS_EX_TOOLWINDOW = 0x00000080,
// ...
}
public enum GetWindowLongFields
{
// ...
GWL_EXSTYLE = (-20),
// ...
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
{
int error = 0;
IntPtr result = IntPtr.Zero;
// Win32 SetWindowLong doesn''t clear error on success
SetLastError(0);
if (IntPtr.Size == 4)
{
// use SetWindowLong
Int32 tempResult = IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong));
error = Marshal.GetLastWin32Error();
result = new IntPtr(tempResult);
}
else
{
// use SetWindowLongPtr
result = IntSetWindowLongPtr(hWnd, nIndex, dwNewLong);
error = Marshal.GetLastWin32Error();
}
if ((result == IntPtr.Zero) && (error != 0))
{
throw new System.ComponentModel.Win32Exception(error);
}
return result;
}
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
private static extern Int32 IntSetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);
private static int IntPtrToInt32(IntPtr intPtr)
{
return unchecked((int)intPtr.ToInt64());
}
[DllImport("kernel32.dll", EntryPoint = "SetLastError")]
public static extern void SetLastError(int dwErrorCode);
#endregion
He sido desarrollador de .NET durante varios años y esta sigue siendo una de esas cosas que no sé cómo hacer correctamente. Es fácil ocultar una ventana de la barra de tareas a través de una propiedad tanto en Windows Forms como en WPF, pero hasta donde puedo decir, esto no garantiza (o incluso afecta) que se oculte desde el cuadro de diálogo Alt + ↹Tab . He visto ventanas invisibles aparecer en Alt + ↹Tab , y me pregunto cuál es la mejor manera de garantizar que una ventana nunca aparecerá (visible o no) en el cuadro de diálogo Alt + ↹Tab .
Actualización: por favor vea mi solución publicada a continuación. No puedo marcar mis propias respuestas como la solución, pero hasta ahora es la única que funciona.
Actualización 2: Ahora hay una solución adecuada de Franci Penov que se ve bastante bien, pero no lo he probado yo mismo. Implica algo de Win32, pero evita la creación coja de ventanas fuera de pantalla.
En el conjunto XAML ShowInTaskbar = "False":
<Window x:Class="WpfApplication5.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShowInTaskbar="False"
Title="Window1" Height="300" Width="300">
<Grid>
</Grid>
</Window>
Editar: Eso todavía se muestra en Alt + Tab, supongo, simplemente no en la barra de tareas.
Personalmente, por lo que yo sé, esto no es posible sin conectarme a las ventanas de alguna manera, ni siquiera estoy seguro de cómo se haría eso o si es posible.
Dependiendo de sus necesidades, desarrollar el contexto de su aplicación como una aplicación NotifyIcon (bandeja del sistema) permitirá que se ejecute sin mostrar en ALT + TAB. SIN EMBARGO, si abre un formulario, ese formulario seguirá la funcionalidad estándar.
Puedo desenterrar el artículo de mi blog sobre la creación de una aplicación que es SOLO un NotifyIcon de forma predeterminada si así lo desea.
No mostrar un formulario Usa la invisibilidad
Más aquí: http://code.msdn.microsoft.com/TheNotifyIconExample
Propiedades de Form1:
FormBorderStyle: considerable
WindowState: minimizado
ShowInTaskbar: False
private void Form1_Load(object sender, EventArgs e)
{
// Making the window invisible forces it to not show up in the ALT+TAB
this.Visible = false;
}>
verlo: (de http://bytes.com/topic/c-sharp/answers/442047-hide-alt-tab-list#post1683880 )
[DllImport("user32.dll")]
public static extern int SetWindowLong( IntPtr window, int index, int
value);
[DllImport("user32.dll")]
public static extern int GetWindowLong( IntPtr window, int index);
const int GWL_EXSTYLE = -20;
const int WS_EX_TOOLWINDOW = 0x00000080;
const int WS_EX_APPWINDOW = 0x00040000;
private System.Windows.Forms.NotifyIcon notifyIcon1;
// I use two icons depending of the status of the app
normalIcon = new Icon(this.GetType(),"Normal.ico");
alertIcon = new Icon(this.GetType(),"Alert.ico");
notifyIcon1.Icon = normalIcon;
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.Visible = false;
this.ShowInTaskbar = false;
iconTimer.Start();
//Make it gone frmo the ALT+TAB
int windowStyle = GetWindowLong(Handle, GWL_EXSTYLE);
SetWindowLong(Handle, GWL_EXSTYLE, windowStyle | WS_EX_TOOLWINDOW);
Intenté establecer la visibilidad del formulario principal en falso siempre que se cambie automáticamente a verdadero:
private void Form1_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible)
{
this.Visible = false;
}
}
Funciona perfectamente :)
¿Por qué probar tantos códigos? Simplemente configure FormBorderStyle
propety en FixedToolWindow
. Espero eso ayude.
si desea que el formulario no tenga bordes, entonces necesita agregar las siguientes declaraciones al constructor del formulario:
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
Y debe agregar el siguiente método a su clase Form derivada:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
// turn on WS_EX_TOOLWINDOW style bit
cp.ExStyle |= 0x80;
return cp;
}
}
Dentro de tu clase de formulario, agrega esto:
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= 0x80;
return Params;
}
}
Es tan fácil como eso; funciona un encanto!
¿Por qué tan complejo? Prueba esto:
me.FormBorderStyle = FormBorderStyle.SizableToolWindow
me.ShowInTaskbar = false
Idea tomada desde aquí: http://www.csharp411.com/hide-form-from-alttab/
Encontré una solución, pero no es bonita. Hasta ahora, esto es lo único que he probado que realmente funciona:
Window w = new Window(); // Create helper window
w.Top = -100; // Location of new window is outside of visible part of screen
w.Left = -100;
w.Width = 1; // size of window is enough small to avoid its appearance at the beginning
w.Height = 1;
w.WindowStyle = WindowStyle.ToolWindow; // Set window style as ToolWindow to avoid its icon in AltTab
w.Show(); // We need to show window before set is as owner to our main window
this.Owner = w; // Okey, this will result to disappear icon for main window.
w.Hide(); // Hide helper window just in case
Lo encontré aquí .
Una solución más general y reutilizable sería agradable. Supongo que podría crear una ventana única ''w'' y reutilizarla para todas las ventanas de su aplicación que necesitan estar ocultas desde Alt + ↹Tab .
Actualización: Ok, lo que hice fue mover el código anterior, menos el this.Owner = w
bit (y mover w.Hide()
inmediatamente después de w.Show()
, que funciona bien) en el constructor de mi aplicación, creando un static público Window
llamada OwnerWindow
. Cada vez que quiero que una ventana muestre este comportamiento, simplemente configuro this.Owner = App.OwnerWindow
. this.Owner = App.OwnerWindow
. Funciona muy bien, y solo implica crear una ventana extra (e invisible). Incluso puede establecer esto. this.Owner = null
si desea que la ventana vuelva a aparecer en el cuadro de diálogo Alt + ↹Tab .
Gracias a Ivan Onuchin en los foros de MSDN para la solución.
Actualización 2: también debe establecer ShowInTaskBar=false
en w
para evitar que destelle brevemente en la barra de tareas cuando se muestre.
Esto es lo que hace el truco, independientemente del estilo de la ventana que intenta ocultar de Alt + ↹Tab .
Coloque lo siguiente en el constructor de su formulario:
// Keep this program out of the Alt-Tab menu
ShowInTaskbar = false;
Form form1 = new Form ( );
form1.FormBorderStyle = FormBorderStyle.FixedToolWindow;
form1.ShowInTaskbar = false;
Owner = form1;
Esencialmente, haces que tu formulario sea secundario de una ventana invisible que tiene el estilo correcto y la configuración ShowInTaskbar para mantenerse fuera de la lista Alt-Tab. También debe establecer la propiedad ShowInTaskbar de su propio formulario en falso. Lo mejor de todo es que simplemente no importa el estilo que tenga tu forma principal, y todos los ajustes para lograr el escondite son solo unas pocas líneas en el código del constructor.