Aktualizacja:
Według @donovan, współczesne WPF obsługuje to natywnie, poprzez ustawienie
ShowInTaskbar="False"
iVisibility="Hidden"
w języku XAML. (Jeszcze tego nie testowałem, ale mimo to postanowiłem zwiększyć widoczność komentarzy)
Oryginalna odpowiedź:
Istnieją dwa sposoby ukrycia okna z przełącznika zadań w Win32 API:
- dodać
WS_EX_TOOLWINDOW
rozszerzony styl okna - to jest właściwe podejście.
- aby było to okno potomne innego okna.
Niestety, WPF nie obsługuje tak elastycznej kontroli nad stylem okna jak Win32, więc okno z WindowStyle=ToolWindow
kończy się na domyślnych WS_CAPTION
i WS_SYSMENU
stylach, co powoduje, że ma podpis i przycisk zamykania. Z drugiej strony możesz usunąć te dwa style, ustawiając WindowStyle=None
, jednak nie spowoduje to ustawieniaWS_EX_TOOLWINDOW
rozszerzonego stylu, a okno nie będzie ukryte przed przełącznikiem zadań.
Aby mieć okno WPF z WindowStyle=None
tym, które jest również ukryte przed przełącznikiem zadań, można wybrać jeden z dwóch sposobów:
- przejdź do powyższego przykładowego kodu i ustaw okno jako okno potomne małego, ukrytego okna narzędzia
- zmodyfikuj styl okna, aby uwzględnić również
WS_EX_TOOLWINDOW
styl rozszerzony.
Osobiście wolę drugie podejście. Z drugiej strony robię zaawansowane rzeczy, takie jak rozszerzenie szyby w obszarze roboczym i i tak włączenie rysowania WPF w podpisie, więc odrobina interopu nie jest dużym problemem.
Oto przykładowy kod rozwiązania międzyoperacyjnego Win32. Najpierw część 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" >
Nic nadzwyczajnego, po prostu deklarujemy okno z WindowStyle=None
i ShowInTaskbar=False
. Dodajemy również procedurę obsługi do zdarzenia Loaded, w którym zmodyfikujemy rozszerzony styl okna. Nie możemy wykonać tej pracy w konstruktorze, ponieważ w tym momencie nie ma jeszcze uchwytu okna. Sam program obsługi zdarzeń jest bardzo prosty:
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);
}
I deklaracje międzyoperacyjne Win32. Usunąłem wszystkie niepotrzebne style z wyliczeń, aby przykładowy kod był mały. Niestety, SetWindowLongPtr
punkt wejścia nie znajduje się w user32.dll w systemie Windows XP, stąd sztuczka z przekierowywaniem połączenia przez ten SetWindowLong
plik.
#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