Aktualisieren:
Laut @donovan unterstützt die moderne WPF dies nativ durch Setzen
ShowInTaskbar="False"
und Visibility="Hidden"
in der XAML. (Ich habe dies noch nicht getestet, aber dennoch beschlossen, die Sichtbarkeit der Kommentare zu erhöhen.)
Ursprüngliche Antwort:
Es gibt zwei Möglichkeiten, ein Fenster vor dem Task-Switcher in der Win32-API auszublenden:
- den
WS_EX_TOOLWINDOW
erweiterten Fensterstil hinzuzufügen - das ist der richtige Ansatz.
- um es zu einem untergeordneten Fenster eines anderen Fensters zu machen.
Leider unterstützt WPF keine so flexible Steuerung des Fensterstils wie Win32, sodass ein Fenster WindowStyle=ToolWindow
mit den Standardeinstellungen WS_CAPTION
und WS_SYSMENU
Stilen endet , was dazu führt, dass es eine Beschriftung und eine Schaltfläche zum Schließen hat. Auf der anderen Seite können Sie diese beiden Stile durch Festlegen entfernen. Dadurch WindowStyle=None
wird jedoch der WS_EX_TOOLWINDOW
erweiterte Stil nicht festgelegt und das Fenster wird nicht vor dem Task-Umschalter ausgeblendet.
Um ein WPF-Fenster zu haben WindowStyle=None
, das auch vor dem Task-Umschalter verborgen ist, gibt es zwei Möglichkeiten:
- Gehen Sie mit dem obigen Beispielcode und machen Sie das Fenster zu einem untergeordneten Fenster eines kleinen versteckten Werkzeugfensters
- Ändern Sie den Fensterstil so, dass er auch den
WS_EX_TOOLWINDOW
erweiterten Stil enthält.
Ich persönlich bevorzuge den zweiten Ansatz. Andererseits mache ich einige fortgeschrittene Dinge wie das Erweitern des Glases im Client-Bereich und das Aktivieren des WPF-Zeichnens in der Beschriftung, sodass ein bisschen Interop kein großes Problem ist.
Hier ist der Beispielcode für den Win32-Interop-Lösungsansatz. Zunächst der XAML-Teil:
<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" >
Nichts Besonderes hier, wir deklarieren nur ein Fenster mit WindowStyle=None
und ShowInTaskbar=False
. Wir fügen dem Loaded-Ereignis auch einen Handler hinzu, in dem wir den erweiterten Fensterstil ändern. Wir können diese Arbeit im Konstruktor nicht ausführen, da es zu diesem Zeitpunkt noch kein Fensterhandle gibt. Der Event-Handler selbst ist sehr einfach:
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);
}
Und die Win32-Interop-Deklarationen. Ich habe alle unnötigen Stile aus den Aufzählungen entfernt, um den Beispielcode hier klein zu halten. Leider befindet sich der SetWindowLongPtr
Einstiegspunkt auch nicht in user32.dll unter Windows XP, daher der Trick beim Weiterleiten des Anrufs über die 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