Aggiornare:
Secondo @donovan, i giorni nostri WPF lo supporta in modo nativo, tramite l'impostazione
ShowInTaskbar="False"
e Visibility="Hidden"
nel XAML. (Non l'ho ancora testato, ma ho comunque deciso di aumentare la visibilità dei commenti)
Risposta originale:
Esistono due modi per nascondere una finestra dal selettore di attività nell'API Win32:
- per aggiungere lo
WS_EX_TOOLWINDOW
stile della finestra estesa: questo è l'approccio giusto.
- per renderlo una finestra figlia di un'altra finestra.
Sfortunatamente, WPF non supporta un controllo flessibile sullo stile della finestra come Win32, quindi una finestra con WindowStyle=ToolWindow
finisce con l'impostazione predefinita WS_CAPTION
e gli WS_SYSMENU
stili, il che fa sì che abbia una didascalia e un pulsante di chiusura. D'altra parte, puoi rimuovere questi due stili impostando WindowStyle=None
, tuttavia ciò non imposterà lo WS_EX_TOOLWINDOW
stile esteso e la finestra non sarà nascosta dal selettore di attività.
Per avere una finestra WPF con WindowStyle=None
che è anche nascosta dal selettore di attività, si può in due modi:
- vai con il codice di esempio sopra e rendi la finestra una finestra figlia di una piccola finestra degli strumenti nascosta
- modificare lo stile della finestra per includere anche lo
WS_EX_TOOLWINDOW
stile esteso.
Personalmente preferisco il secondo approccio. Poi di nuovo, eseguo alcune cose avanzate come estendere il vetro nell'area client e abilitare comunque il disegno WPF nella didascalia, quindi un po 'di interoperabilità non è un grosso problema.
Ecco il codice di esempio per l'approccio alla soluzione di interoperabilità Win32. Innanzitutto, 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" >
Niente di speciale qui, dichiariamo solo una finestra con WindowStyle=None
e ShowInTaskbar=False
. Aggiungiamo anche un gestore all'evento Loaded dove modificheremo lo stile della finestra estesa. Non possiamo fare quel lavoro nel costruttore, poiché non ci sono ancora handle di finestra a quel punto. Il gestore di eventi stesso è molto semplice:
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 le dichiarazioni di interoperabilità Win32. Ho rimosso tutti gli stili non necessari dalle enumerazioni, solo per mantenere piccolo il codice di esempio. Inoltre, sfortunatamente il SetWindowLongPtr
punto di ingresso non si trova in user32.dll su Windows XP, da qui il trucco con l'instradamento della chiamata attraverso SetWindowLong
invece.
#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