Atualizar:
De acordo com @donovan, o WPF moderno dá suporte a isso nativamente, por meio da configuração
ShowInTaskbar="False"
e Visibility="Hidden"
no XAML. (Eu não testei isso ainda, mas decidi aumentar a visibilidade do comentário)
Resposta original:
Existem duas maneiras de ocultar uma janela do alternador de tarefas na API Win32:
- para adicionar o
WS_EX_TOOLWINDOW
estilo de janela estendida - essa é a abordagem certa.
- para torná-la uma janela filha de outra janela.
Infelizmente, o WPF não oferece suporte a um controle tão flexível sobre o estilo de janela como o Win32, portanto, uma janela WindowStyle=ToolWindow
com o padrão WS_CAPTION
e WS_SYSMENU
estilos, o que faz com que tenha uma legenda e um botão Fechar. Por outro lado, você pode remover esses dois estilos configurando WindowStyle=None
, no entanto, isso não definirá o WS_EX_TOOLWINDOW
estilo estendido e a janela não ficará oculta do alternador de tarefas.
Para ter uma janela WPF WindowStyle=None
que também está oculta do alternador de tarefas, pode-se de duas maneiras:
- vá com o código de exemplo acima e torne a janela uma janela filha de uma pequena janela de ferramenta oculta
- modifique o estilo da janela para incluir também o
WS_EX_TOOLWINDOW
estilo estendido.
Eu pessoalmente prefiro a segunda abordagem. Então, novamente, eu faço algumas coisas avançadas como estender o vidro na área do cliente e habilitar o desenho WPF na legenda de qualquer maneira, então um pouco de interoperabilidade não é um grande problema.
Aqui está o código de exemplo para a abordagem de solução de interoperabilidade Win32. Primeiro, a 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" >
Nada muito sofisticado aqui, apenas declaramos uma janela com WindowStyle=None
e ShowInTaskbar=False
. Também adicionamos um manipulador ao evento Loaded, onde modificaremos o estilo da janela estendida. Não podemos fazer esse trabalho no construtor, pois ainda não há nenhum identificador de janela nesse ponto. O próprio manipulador de eventos é muito simples:
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);
}
E as declarações de interoperabilidade do Win32. Removi todos os estilos desnecessários dos enums, apenas para manter pequeno o código de amostra aqui. Além disso, infelizmente, o SetWindowLongPtr
ponto de entrada não foi encontrado em user32.dll no Windows XP, daí o truque de rotear a chamada através do 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