Der beste Weg, um ein Fenster vor dem Alt-Tab-Programmumschalter auszublenden?

100

Ich bin jetzt seit mehreren Jahren ein .NET-Entwickler und dies ist immer noch eines der Dinge, die ich nicht richtig machen kann. Es ist einfach, ein Fenster über eine Eigenschaft in Windows Forms und WPF vor der Taskleiste auszublenden, aber soweit ich das beurteilen kann, kann dies nicht garantieren (oder sogar beeinflussen), dass es im Dialogfeld Alt+ ausgeblendet wird ↹Tab. Ich habe gesehen, dass unsichtbare Fenster in Alt+ ↹Tabangezeigt werden, und ich frage mich nur, wie ich am besten sicherstellen kann, dass ein Fenster niemals im Alt+ ↹TabDialogfeld angezeigt wird (sichtbar oder nicht) .

Update: Bitte beachten Sie meine unten stehende Lösung. Ich darf meine eigenen Antworten nicht als Lösung markieren, aber bisher ist es die einzige, die funktioniert.

Update 2: Es gibt jetzt eine richtige Lösung von Franci Penov, die ziemlich gut aussieht, sie aber nicht selbst ausprobiert hat. Enthält einige Win32, vermeidet jedoch die lahme Erstellung von Off-Screen-Fenstern.

devios1
quelle
13
System Tray Apps sind ein
gutes
3
Ich möchte dies aus einem Grund tun, weil ich ein halbtransparentes Schwarzfenster im Vollbildmodus verwende, um einen "Dimm" -Effekt zu erzielen, wenn meine App eine modale Oberfläche anzeigt, ähnlich wie im UAC-Dialogfeld. Da dies kein interaktives Fenster ist, macht es keinen Sinn, es im Alt-Tab-Dialogfeld anzuzeigen.
devios1
8
Ich würde empfehlen, den gesamten Desktop nicht zu dimmen, wenn Ihre App einen eigenen modalen Dialog anzeigt. Das Dimmen des Desktops schlägt eine Operation auf Betriebssystemebene vor. Die meisten Leute hätten nicht genug Wissen, um zu verstehen, dass es sich nicht um den sicheren Desktop handelt.
Franci Penov
3
"Es ist einfach, ein Fenster über eine Eigenschaft in der Taskleiste auszublenden". Diese Eigenschaft ist ShowInTaskbar (nur für den Datensatz).
Greenoldman
Bei der Frage geht es darum, das Fenster vor Alt-Tab und nicht vor Taskleiste auszublenden.
Alexandru Dicu

Antworten:

93

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:

  1. den WS_EX_TOOLWINDOWerweiterten Fensterstil hinzuzufügen - das ist der richtige Ansatz.
  2. 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=ToolWindowmit den Standardeinstellungen WS_CAPTIONund WS_SYSMENUStilen 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=Nonewird jedoch der WS_EX_TOOLWINDOWerweiterte 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_TOOLWINDOWerweiterten 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=Noneund 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 SetWindowLongPtrEinstiegspunkt 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
Franci Penov
quelle
2
Ich habe das nicht überprüft, aber es hört sich so an, als ob Sie wissen, wovon Sie sprechen. :) Ich werde das im Hinterkopf behalten, wenn ich es noch einmal tun muss, aber da meine andere Lösung gut funktioniert (und es eine Weile her ist, seit ich das Buch über dieses geschlossen habe), möchte ich nicht herumspielen und etwas kaputt machen . Vielen Dank!
devios1
1
Funktioniert perfekt! Vielen Dank!
Anthony Brien
Funktioniert gut für mich. Aber ich hasse es, DLL wie
folgt
8
@ J4N - Es ist nichts falsch mit ein bisschen P / Invoke hin und wieder :-)
Franci Penov
1
Dies hat bei mir in WPF nicht funktioniert. Aber nachdem ich herumgespielt hatte, fand ich eine viel einfachere Lösung darin, ShowInTaskbar = "False" und Visibility = "Hidden" in der XAML zu setzen. Kein spezieller Pinvoke erforderlich.
Donovan
40

Fügen Sie in Ihrer Formularklasse Folgendes hinzu:

protected override CreateParams CreateParams
{
    get
    {
        var Params = base.CreateParams;
        Params.ExStyle |= 0x80;
        return Params;
    }
}

So einfach ist das; wirkt ein Zauber!

Danny Beckett
quelle
3
Außerdem muss ShowInTaskbar auf false gesetzt werden, damit dies funktioniert.
Nick Spreitzer
20

Ich habe eine Lösung gefunden, aber sie ist nicht schön. Bisher ist dies das einzige, was ich ausprobiert habe, das tatsächlich funktioniert:

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

Fand es hier .

Eine allgemeinere, wiederverwendbare Lösung wäre schön. Ich nehme an, Sie könnten ein einzelnes Fenster 'w' erstellen und es für alle Fenster in Ihrer App wiederverwenden, die vor dem Alt+ ausgeblendet werden müssen ↹Tab.

Update: Ok, also habe ich den obigen Code abzüglich des this.Owner = wBits (und w.Hide()unmittelbar danach w.Show(), was gut funktioniert) in den Konstruktor meiner Anwendung verschoben und eine öffentliche Statik Windownamens erstellt OwnerWindow. Wann immer ich möchte, dass ein Fenster dieses Verhalten zeigt, setze ich einfach this.Owner = App.OwnerWindow. Funktioniert hervorragend und umfasst nur das Erstellen eines zusätzlichen (und unsichtbaren) Fensters. Sie können sogar festlegen, this.Owner = nullob das Fenster im Dialogfeld Alt+ erneut ↹Tabangezeigt werden soll.

Vielen Dank an Ivan Onuchin in den MSDN-Foren für die Lösung.

Update 2: Sie sollten auch eingestellt ShowInTaskBar=falseauf , wdamit er nicht kurz in der Taskleiste zu blinken , wenn gezeigt.

devios1
quelle
Es gibt auch eine Win32-Interop-Lösung für dieses Problem.
Franci Penov
Interessant, ich mache diesen Ansatz, aber vermeide das versteckte Fenster (mit dem Haupt-App-Fenster als Eigentümer), und es erscheint nicht in Alt-Tab ...
Dave
1
Ich denke, bei Konfigurationen mit zwei Monitoren kann der zweite Bildschirm auch negative Koordinaten haben.
Thomas Weller
@ ThomasW. Du hast wahrscheinlich Recht. Die Verwendung eines Versatzes wie -100000wäre wahrscheinlich besser.
Devios1
Dies ist wirklich ein schlechter Hack für dieses Problem.
Alexandru Dicu
10

Warum so komplex? Versuche dies:

me.FormBorderStyle = FormBorderStyle.SizableToolWindow
me.ShowInTaskbar = false

Idee von hier übernommen: http://www.csharp411.com/hide-form-from-alttab/

Andrey
quelle
Funktioniert bei mir. Danke für den Beitrag!
MiBol
Ein ToolWindow kann jedoch nicht maximiert oder minimiert werden. Ein ToolWindow ist nicht immer eine bevorzugte Option.
Alexandru Dicu
10

Hier ist der Trick, unabhängig vom Stil des Fensters, vor dem Sie sich verstecken Altmöchten ↹Tab.

Fügen Sie Folgendes in den Konstruktor Ihres Formulars ein:

// Keep this program out of the Alt-Tab menu

ShowInTaskbar = false;

Form form1 = new Form ( );

form1.FormBorderStyle = FormBorderStyle.FixedToolWindow;
form1.ShowInTaskbar = false;

Owner = form1;

Im Wesentlichen machen Sie Ihr Formular zu einem untergeordneten Element eines unsichtbaren Fensters, das den richtigen Stil und die richtige ShowInTaskbar-Einstellung hat, um nicht in die Alt-Tab-Liste aufgenommen zu werden. Sie müssen auch die ShowInTaskbar-Eigenschaft Ihres eigenen Formulars auf false setzen. Das Beste ist, dass es einfach keine Rolle spielt, welchen Stil Ihr Hauptformular hat, und alle Optimierungen, um das Ausblenden zu erreichen, sind nur ein paar Zeilen im Konstruktorcode.

Matt Hendricks
quelle
Warten Sie ... ist DIESES ein C # oder C oder C ++ ??? Ich bin wirklich ein n00b bei der C-Familie oder was auch immer ...
Sreenikethan I
3

Warum so viele Codes ausprobieren? FormBorderStyleStellen Sie einfach die Eigenschaft auf FixedToolWindow. Ich hoffe es hilft.

Saravanakumar. N.
quelle
2

siehe es: (von 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);
Behnam Shomali
quelle
Ich würde hier hinzufügen, dass 'Handle' von var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu
1

In XAML setze 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>

Bearbeiten: Das zeigt es immer noch in Alt + Tab, nur nicht in der Taskleiste.

Philipp Schmid
quelle
Ja, das ist das Problem: ShowInTaskbar wirkt sich nicht wie erwartet auf das Alt + Tab-Dialogfeld aus.
devios1
1

Ich habe versucht, die Sichtbarkeit des Hauptformulars auf false zu setzen, wenn es automatisch in true geändert wird:

private void Form1_VisibleChanged(object sender, EventArgs e)
{
    if (this.Visible)
    {
        this.Visible = false;
    }
}

Es funktioniert perfekt :)

Tiendan
quelle
2
Dies ist nicht nur bei weitem die einfachste Lösung, sondern hat auch sehr gut für mich funktioniert.
Daniel McQuiston
1

Wenn das Formular randlos sein soll, müssen Sie dem Konstruktor des Formulars die folgenden Anweisungen hinzufügen:

this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;

UND Sie müssen Ihrer abgeleiteten Formularklasse die folgende Methode hinzufügen:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        // turn on WS_EX_TOOLWINDOW style bit
        cp.ExStyle |= 0x80;
        return cp;
    }
}

mehr Details

Hossein Moradinia
quelle
0

Form1-Eigenschaften:
FormBorderStyle: Sizable
WindowState: Minimiert
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;
}>
Charlie Salts
quelle
-1

Persönlich, soweit ich weiß, ist dies nicht möglich, ohne sich in irgendeiner Weise in Fenster einzuhängen. Ich bin mir nicht einmal sicher, wie das gemacht werden würde oder ob es möglich ist.

Je nach Ihren Anforderungen können Sie Ihren Anwendungskontext als NotifyIcon-Anwendung (Taskleiste) ausführen, ohne dass er in ALT + TAB angezeigt wird. Wenn Sie jedoch ein Formular öffnen, folgt dieses Formular weiterhin der Standardfunktionalität.

Ich kann meinen Blog-Artikel über das Erstellen einer Anwendung lesen, die standardmäßig NUR ein NotifyIcon ist, wenn Sie möchten.

Mitchel Sellers
quelle
Ich bin bereits mit NotifyIcons vertraut, danke. Das Problem ist, dass ich geöffnete (nicht interaktive oder oberste) Fenster vor Alt + Tab ausblenden möchte. Interessanterweise ist mir gerade aufgefallen, dass die Vista-Seitenleiste nicht in Alt + Tab angezeigt wird, daher muss es einige Möglichkeiten geben, dies zu tun.
devios1
Wenn ich mir die verschiedenen Teile ansehe, ohne den Fenstertyp zu ändern (wie Redbeard geschrieben hat), weiß ich nicht, wie ich das tun kann.
Mitchel Sellers