วิธีที่ดีที่สุดในการซ่อนหน้าต่างจากตัวสลับโปรแกรม Alt-Tab?


101

ฉันเป็นนักพัฒนา. NET มาหลายปีแล้วและนี่ก็ยังคงเป็นหนึ่งในสิ่งเหล่านั้นที่ฉันไม่รู้ว่าต้องทำอย่างไร เป็นเรื่องง่ายที่จะซ่อนหน้าต่างจากแถบงานผ่านคุณสมบัติทั้งใน Windows Forms และ WPF แต่เท่าที่ฉันสามารถบอกได้สิ่งนี้ไม่ได้รับประกันว่า (หรือจำเป็นต้องมีผลต่อ) ว่าจะถูกซ่อนจากกล่องโต้ตอบAlt+ ↹Tabฉันเคยเห็นหน้าต่างที่มองไม่เห็นปรากฏในAlt+ ↹Tabและฉันแค่สงสัยว่าอะไรคือวิธีที่ดีที่สุดในการรับประกันว่าหน้าต่างจะไม่ปรากฏ (มองเห็นได้หรือไม่) ในกล่องโต้ตอบAlt+↹Tab

อัปเดต:โปรดดูวิธีแก้ปัญหาที่โพสต์ไว้ด้านล่าง ฉันไม่ได้รับอนุญาตให้ทำเครื่องหมายคำตอบของตัวเองเป็นคำตอบ แต่จนถึงตอนนี้มันเป็นคำตอบเดียวที่ใช้ได้ผล

อัปเดต 2:ตอนนี้ Franci Penov มีวิธีแก้ปัญหาที่เหมาะสมซึ่งดูดีมาก แต่ยังไม่ได้ลองด้วยตัวเอง เกี่ยวข้องกับ Win32 บางตัว แต่หลีกเลี่ยงการสร้างหน้าต่างนอกหน้าจอที่ง่อย ๆ


13
แอพ System Tray เป็นตัวอย่างที่ยอดเยี่ยม
TravisO

3
ฉันต้องการทำด้วยเหตุผลเดียวเพราะฉันใช้หน้าต่างสีดำกึ่งโปร่งใสแบบเต็มหน้าจอเพื่อให้เอฟเฟกต์ "ลดแสง" เมื่อแอปของฉันแสดงอินเทอร์เฟซแบบโมดอลซึ่งเหมือนกับกล่องโต้ตอบ UAC เนื่องจากนี่ไม่ใช่หน้าต่างโต้ตอบจึงไม่มีจุดใดที่แสดงในกล่องโต้ตอบ Alt-Tab
devios1

8
ฉันขอแนะนำไม่ให้ลดแสงเดสก์ท็อปทั้งหมดเมื่อแอปของคุณแสดงกล่องโต้ตอบโมดอลของตัวเอง การหรี่เดสก์ท็อปจะแนะนำการใช้งานระดับ OS คนส่วนใหญ่ไม่มีความรู้เพียงพอที่จะเข้าใจได้ว่าไม่ใช่เดสก์ท็อปที่ปลอดภัย
Franci Penov

3
"การซ่อนหน้าต่างจากแถบงานผ่านคุณสมบัติ" เป็นเรื่องง่าย คุณสมบัตินี้คือ ShowInTaskbar (สำหรับบันทึกเท่านั้น)
greenoldman

คำถามเกี่ยวกับการซ่อนหน้าต่างจาก Alt-Tab ไม่ใช่จากแถบงาน
Alexandru Dicu

คำตอบ:


94

อัปเดต:

ตามที่ @donovan WPF ยุคปัจจุบันสนับสนุนสิ่งนี้โดยกำเนิดผ่านการตั้งค่า ShowInTaskbar="False"และVisibility="Hidden"ใน XAML (ฉันยังไม่ได้ทดสอบ แต่อย่างไรก็ตามตัดสินใจที่จะชนการแสดงความคิดเห็น)

คำตอบเดิม:

มีสองวิธีในการซ่อนหน้าต่างจากตัวสลับงานใน Win32 API:

  1. เพื่อเพิ่มWS_EX_TOOLWINDOWสไตล์หน้าต่างขยายนั่นคือแนวทางที่ถูกต้อง
  2. เพื่อทำให้เป็นหน้าต่างย่อยของหน้าต่างอื่น

น่าเสียดายที่ WPF ไม่รองรับการควบคุมรูปแบบหน้าต่างที่ยืดหยุ่นเท่ากับ Win32 ดังนั้นหน้าต่างที่มีWindowStyle=ToolWindowค่าเริ่มต้นWS_CAPTIONและWS_SYSMENUสไตล์ซึ่งทำให้มีคำอธิบายภาพและปุ่มปิด ในทางกลับกันคุณสามารถลบสองสไตล์นี้ได้โดยการตั้งค่าWindowStyle=Noneอย่างไรก็ตามจะไม่ตั้งค่าWS_EX_TOOLWINDOWรูปแบบขยายและหน้าต่างจะไม่ถูกซ่อนจากตัวสลับงาน

หากต้องการมีหน้าต่าง WPF WindowStyle=Noneที่ซ่อนอยู่จากตัวสลับงานสามารถทำได้สองวิธี:

  • ไปกับโค้ดตัวอย่างด้านบนและทำให้หน้าต่างเป็นหน้าต่างย่อยของหน้าต่างเครื่องมือขนาดเล็กที่ซ่อนอยู่
  • ปรับเปลี่ยนสไตล์หน้าต่างเพื่อรวมWS_EX_TOOLWINDOWสไตล์เพิ่มเติมด้วย

โดยส่วนตัวแล้วฉันชอบแนวทางที่สองมากกว่า จากนั้นอีกครั้งฉันทำสิ่งขั้นสูงบางอย่างเช่นการขยายกระจกในพื้นที่ไคลเอนต์และเปิดใช้งานการวาด WPF ในคำบรรยายภาพดังนั้นการทำงานร่วมกันเล็กน้อยจึงไม่ใช่ปัญหาใหญ่

นี่คือโค้ดตัวอย่างสำหรับแนวทางการแก้ปัญหาการทำงานร่วมกันของ Win32 ขั้นแรกส่วน 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" >

ไม่มีอะไรเกินไปแฟนซีที่นี่เราก็ประกาศหน้าต่างด้วยและWindowStyle=None ShowInTaskbar=Falseนอกจากนี้เรายังเพิ่มตัวจัดการให้กับเหตุการณ์ Loaded ซึ่งเราจะปรับเปลี่ยนรูปแบบหน้าต่างขยาย เราไม่สามารถทำงานนั้นในตัวสร้างได้เนื่องจากยังไม่มีที่จับหน้าต่างในตอนนั้น ตัวจัดการเหตุการณ์นั้นง่ายมาก:

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);
}

และการประกาศการทำงานร่วมกันของ Win32 ฉันได้ลบรูปแบบที่ไม่จำเป็นทั้งหมดออกจาก enums เพียงเพื่อให้โค้ดตัวอย่างมีขนาดเล็ก นอกจากนี้น่าเสียดายที่SetWindowLongPtrไม่พบจุดเข้าใช้งานใน user32.dll บน Windows XP ดังนั้นเคล็ดลับด้วยการกำหนดเส้นทางการโทรผ่าน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

2
ยังไม่ได้ตรวจสอบ แต่ดูเหมือนคุณจะรู้ว่าคุณกำลังพูดถึงอะไร :) ฉันจะจำสิ่งนี้ไว้หากต้องทำอีกครั้ง แต่เนื่องจากโซลูชันอื่นของฉันใช้งานได้ดี (และเป็นเวลานานแล้วที่ฉันปิดหนังสือเล่มนี้) ฉันไม่ต้องการเล่นซอและทำลายบางสิ่ง . ขอบคุณ!
devios1

1
ทำงานได้อย่างสมบูรณ์แบบ! ขอบคุณ!
Anthony Brien

ใช้งานได้ดีสำหรับฉัน แต่ฉันเกลียดที่ต้องนำเข้า dll แบบนี้: P
J4N

8
@ J4N - ไม่มีอะไรผิดปกติกับ P / Invoke เล็กน้อย :-)
Franci Penov

1
สิ่งนี้ไม่ได้ผลสำหรับฉันใน WPF แต่หลังจากเล่นไปเรื่อย ๆ ฉันพบวิธีแก้ปัญหาที่ง่ายกว่ามากคือตั้ง ShowInTaskbar = "False" และ Visibility = "Hidden" ใน XAML ไม่จำเป็นต้องใช้หมุดพิเศษ
donovan

40

ภายในคลาสฟอร์มของคุณให้เพิ่มสิ่งนี้:

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

        return Params;
    }
}

ง่ายอย่างนั้น มีเสน่ห์!


3
นอกจากนี้ยังต้องตั้งค่า ShowInTaskbar เป็นเท็จเพื่อให้สามารถใช้งานได้
Nick Spreitzer

20

เคยเจอวิธีแก้แล้วแต่มันไม่สวย จนถึงตอนนี้นี่เป็นสิ่งเดียวที่ฉันได้ลองใช้งานได้จริง:

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

พบได้ที่นี่ที่นี่

วิธีแก้ปัญหาที่ใช้ซ้ำได้ทั่วไปจะดีกว่า ฉันคิดว่าคุณสามารถสร้างหน้าต่างเดียว 'w' และนำมาใช้มันสำหรับหน้าต่างทั้งหมดใน app ของคุณที่จะต้องมีการซ่อนจาก+Alt↹Tab

ปรับปรุง:ตกลงดังนั้นสิ่งที่ผมทำก็คือการย้ายโค้ดข้างต้นลบthis.Owner = wบิต (และการเคลื่อนย้ายw.Hide()ทันทีหลังจากw.Show()ที่ทำงานดี) ลงในตัวสร้างแอพลิเคชันของฉันสร้างสาธารณะคงเรียกว่าWindow เมื่อใดก็ตามที่ฉันต้องการหน้าต่างเพื่อแสดงพฤติกรรมนี้ผมเพียงแค่ตั้งOwnerWindow this.Owner = App.OwnerWindowใช้งานได้ดีและเกี่ยวข้องกับการสร้างหน้าต่างพิเศษ (และมองไม่เห็น) เพียงหน้าต่างเดียว คุณสามารถตั้งค่าได้this.Owner = nullว่าต้องการให้หน้าต่างปรากฏขึ้นอีกครั้งในกล่องโต้ตอบAlt+ ↹Tabหรือไม่

ขอบคุณ Ivan Onuchin ในฟอรัม MSDN สำหรับการแก้ปัญหา

การปรับปรุงที่ 2:คุณควรตั้งShowInTaskBar=falseบนwเพื่อป้องกันไม่ให้กระพริบสั้น ๆ ในแถบงานเมื่อแสดง


นอกจากนี้ยังมีโซลูชันการทำงานร่วมกันของ Win32 สำหรับปัญหานั้น
Franci Penov

น่าสนใจฉันกำลังทำวิธีนี้ แต่หลีกเลี่ยงหน้าต่างที่ซ่อนอยู่ (โดยใช้หน้าต่างแอปหลักเป็นเจ้าของ) และไม่ปรากฏใน Alt-Tab ...
Dave

1
ฉันคิดว่าในการกำหนดค่าจอภาพคู่หน้าจอที่สองอาจมีพิกัดเชิงลบ
Thomas Weller

อ. คุณคงพูดถูก ใช้ offset like -100000น่าจะดีกว่า
devios1

นี่เป็นการแฮ็กที่ไม่ดีสำหรับปัญหานี้
Alexandru Dicu

10

ทำไมซับซ้อน? ลองสิ่งนี้:

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

ไอเดียนำมาจากที่นี่: http://www.csharp411.com/hide-form-from-alttab/


เหมาะสำหรับฉัน ขอบคุณสำหรับการสนับสนุน!
MiBol

แต่ ToolWindow ไม่สามารถขยายหรือย่อขนาดได้ ToolWindow ไม่ใช่ตัวเลือกที่ดีกว่าเสมอไป
Alexandru Dicu

10

นี่คือสิ่งที่ไม่หลอกลวงไม่คำนึงถึงรูปแบบของหน้าต่างของคุณกำลังพยายามที่จะซ่อนตัวจาก+Alt↹Tab

วางสิ่งต่อไปนี้ลงในตัวสร้างแบบฟอร์มของคุณ:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

โดยพื้นฐานแล้วคุณทำให้ฟอร์มของคุณเป็นลูกของหน้าต่างที่มองไม่เห็นซึ่งมีสไตล์ที่ถูกต้องและการตั้งค่า ShowInTaskbar เพื่อไม่ให้อยู่ในรายการ Alt-Tab คุณต้องตั้งค่าคุณสมบัติ ShowInTaskbar ของฟอร์มของคุณเองเป็นเท็จ เหนือสิ่งอื่นใดมันไม่สำคัญว่ารูปแบบหลักของคุณจะมีสไตล์ใดและการปรับแต่งทั้งหมดเพื่อให้การซ่อนสำเร็จนั้นเป็นเพียงไม่กี่บรรทัดในโค้ดตัวสร้าง


เดี๋ยวก่อน ... นี่คือ C # หรือ C หรือ C ++ ??? ฉันเป็น n00b ที่ตระกูล C หรืออะไรก็ตาม ...
Sreenikethan ฉัน


2

ดูได้ที่: (จาก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);

ฉันจะเพิ่มที่นี่ว่า 'Handle' สามารถรับได้โดย var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu

1

ใน XAML ตั้ง 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>

แก้ไข: ยังคงแสดงอยู่ใน Alt + Tab ฉันเดาว่าไม่ใช่ในแถบงาน


ใช่นั่นคือปัญหา: ShowInTaskbar ไม่มีผลต่อกล่องโต้ตอบ Alt + Tab อย่างที่คุณคาดหวัง
devios1

1

ฉันพยายามตั้งค่าการมองเห็นของฟอร์มหลักเป็นเท็จเมื่อใดก็ตามที่เปลี่ยนเป็นจริงโดยอัตโนมัติ:

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

ทำงานได้อย่างสมบูรณ์ :)


2
ไม่เพียง แต่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดเท่านั้น แต่ยังได้ผลดีสำหรับฉันด้วย
Daniel McQuiston

1

หากคุณต้องการให้แบบฟอร์มไร้ขอบคุณต้องเพิ่มคำสั่งต่อไปนี้ในตัวสร้างแบบฟอร์ม:

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

และคุณต้องเพิ่มวิธีการต่อไปนี้ในคลาส Form ที่ได้รับของคุณ:

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

รายละเอียดเพิ่มเติม



0

คุณสมบัติ Form1:
FormBorderStyle:
WindowState ที่ปรับขนาดได้: Minimized
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;
}>

-1

โดยส่วนตัวแล้วเท่าที่ฉันรู้ว่าสิ่งนี้เป็นไปไม่ได้หากไม่มีการเชื่อมต่อหน้าต่างในบางรูปแบบฉันไม่แน่ใจด้วยซ้ำว่าจะทำได้อย่างไรหรือเป็นไปได้

ขึ้นอยู่กับความต้องการของคุณการพัฒนาบริบทแอปพลิเคชันของคุณเป็นแอปพลิเคชัน NotifyIcon (ถาดระบบ) จะช่วยให้สามารถทำงานได้โดยไม่ต้องแสดงใน ALT + TAB อย่างไรก็ตามหากคุณเปิดแบบฟอร์มแบบฟอร์มนั้นจะยังคงเป็นไปตามฟังก์ชันการทำงานมาตรฐาน

ฉันสามารถขุดบทความบล็อกของฉันเกี่ยวกับการสร้างแอปพลิเคชันที่เป็นเฉพาะ NotifyIcon ตามค่าเริ่มต้นหากคุณต้องการ


คุณหมายถึงอันนี้เหรอ mitchelsellers.com/blogs/articletype/articleview/articleid/…
Steven A. Lowe

ฉันมีความเชี่ยวชาญใน NotifyIcons อยู่แล้วขอบคุณ ปัญหาคือฉันต้องการซ่อนหน้าต่างที่เปิดอยู่ (ไม่โต้ตอบหรือบนสุด) จาก Alt + Tab ที่น่าสนใจคือฉันเพิ่งสังเกตว่าแถบด้านข้างของ Vista ไม่ปรากฏใน Alt + Tab ดังนั้นจึงต้องมีวิธีการบางอย่าง
devios1

เมื่อมองไปที่บิตและชิ้นส่วนต่างๆโดยไม่ต้องเปลี่ยนประเภทของหน้าต่าง (ตามที่ redbeard โพสต์) ฉันไม่รู้วิธีการทำเช่นนี้
ผู้ขายมิทเชล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.