Cách tốt nhất để ẩn một cửa sổ khỏi trình chuyển đổi chương trình Alt-Tab?


101

Tôi đã là nhà phát triển .NET được vài năm rồi và đây vẫn là một trong những điều tôi không biết phải làm thế nào cho đúng. Thật dễ dàng để ẩn một cửa sổ khỏi thanh tác vụ thông qua một thuộc tính trong cả Windows Forms và WPF, nhưng theo như tôi có thể nói, điều này không đảm bảo (hoặc thậm chí ảnh hưởng) nó bị ẩn khỏi hộp thoại Alt+ ↹Tab. Tôi đã thấy các cửa sổ vô hình hiển thị trong Alt+ ↹Tabvà tôi chỉ tự hỏi đâu là cách tốt nhất để đảm bảo một cửa sổ sẽ không bao giờ xuất hiện (hiển thị hoặc không) trong hộp thoại Alt+ ↹Tab.

Cập nhật: Vui lòng xem giải pháp đã đăng của tôi bên dưới. Tôi không được phép đánh dấu câu trả lời của chính mình là giải pháp, nhưng cho đến nay đó là câu trả lời duy nhất hoạt động.

Cập nhật 2: Hiện đã có một giải pháp thích hợp của Franci Penov có vẻ khá tốt, nhưng bản thân tôi vẫn chưa thử. Liên quan đến một số Win32, nhưng tránh tạo ra các cửa sổ ngoài màn hình một cách khập khiễng.


13
Ứng dụng Khay hệ thống là một ví dụ tuyệt vời
TravisO 10/12/08

3
Tôi muốn làm điều đó vì một lý do vì tôi sử dụng cửa sổ màu đen bán trong suốt toàn màn hình để cung cấp hiệu ứng "làm mờ" khi ứng dụng của tôi hiển thị giao diện phương thức, giống như hộp thoại UAC. Vì đây không phải là một cửa sổ tương tác nên không có điểm nào hiển thị nó trong hộp thoại Alt-Tab.
defos1

8
Tôi khuyên bạn không nên làm mờ toàn bộ màn hình khi ứng dụng của bạn hiển thị hộp thoại phương thức của riêng nó. Làm mờ màn hình đề xuất một hoạt động cấp hệ điều hành. Hầu hết mọi người sẽ không có đủ kiến ​​thức để có thể hiểu nó không phải là máy tính để bàn an toàn.
Franci Penov

3
"Thật dễ dàng để ẩn một cửa sổ khỏi thanh tác vụ thông qua một thuộc tính". Thuộc tính này là ShowInTaskbar (chỉ dành cho bản ghi).
greenoldman,

Câu hỏi là về cách ẩn cửa sổ khỏi Alt-Tab, không phải từ Thanh tác vụ.
Alexandru Dicu

Câu trả lời:


93

Cập nhật:

Theo @donovan, ngày nay WPF hỗ trợ điều này nguyên bản, thông qua cài đặt ShowInTaskbar="False"Visibility="Hidden"trong XAML. (Tôi chưa thử nghiệm điều này, nhưng tuy nhiên, tôi quyết định tăng khả năng hiển thị nhận xét)

Câu trả lời ban đầu:

Có hai cách để ẩn một cửa sổ khỏi trình chuyển đổi tác vụ trong Win32 API:

  1. để thêm WS_EX_TOOLWINDOWkiểu cửa sổ mở rộng - đó là cách tiếp cận phù hợp.
  2. để biến nó thành một cửa sổ con của một cửa sổ khác.

Thật không may, WPF không hỗ trợ kiểm soát linh hoạt kiểu cửa sổ như Win32, do đó, một cửa sổ WindowStyle=ToolWindowkết thúc với kiểu WS_CAPTIONWS_SYSMENUkiểu mặc định , khiến nó có chú thích và nút đóng. Mặt khác, bạn có thể loại bỏ hai kiểu này bằng cách cài đặt WindowStyle=None, tuy nhiên điều đó sẽ không đặt WS_EX_TOOLWINDOWkiểu mở rộng và cửa sổ sẽ không bị ẩn khỏi trình chuyển đổi tác vụ.

Để có một cửa sổ WPF WindowStyle=Nonecũng bị ẩn khỏi trình chuyển đổi tác vụ, bạn có thể thực hiện một trong hai cách:

  • đi với mã mẫu ở trên và đặt cửa sổ thành cửa sổ con của một cửa sổ công cụ ẩn nhỏ
  • sửa đổi kiểu cửa sổ để bao gồm cả WS_EX_TOOLWINDOWkiểu mở rộng.

Cá nhân tôi thích cách tiếp cận thứ hai hơn. Sau đó, một lần nữa, tôi thực hiện một số công việc nâng cao như mở rộng kính trong khu vực khách hàng và bật bản vẽ WPF trong chú thích, vì vậy một chút tương tác không phải là vấn đề lớn.

Đây là mã mẫu cho cách tiếp cận giải pháp tương tác Win32. Đầu tiên, phần 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" >

Không có gì quá lạ mắt ở đây, chúng tôi chỉ khai báo một cửa sổ với WindowStyle=NoneShowInTaskbar=False. Chúng tôi cũng thêm một trình xử lý vào sự kiện Đã tải, nơi chúng tôi sẽ sửa đổi kiểu cửa sổ mở rộng. Chúng tôi không thể thực hiện công việc đó trong hàm tạo, vì chưa có cửa sổ xử lý tại thời điểm đó. Bản thân trình xử lý sự kiện rất đơn giản:

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

Và các khai báo Interop Win32. Tôi đã xóa tất cả các kiểu không cần thiết khỏi enum, chỉ để giữ cho mã mẫu ở đây nhỏ. Ngoài ra, không may là SetWindowLongPtrđiểm nhập không được tìm thấy trong user32.dll trên Windows XP, do đó, mẹo định tuyến cuộc gọi thông qua SetWindowLongthay thế.

#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
Chưa xác minh điều này nhưng có vẻ như bạn biết mình đang nói về điều gì. :) Tôi sẽ ghi nhớ điều này nếu tôi cần phải làm lại, nhưng vì giải pháp khác của tôi đang hoạt động tốt (và đã lâu tôi đóng sách về giải pháp này) nên tôi không muốn loay hoay và phá vỡ điều gì đó . Cảm ơn!
defos1

1
Hoạt động hoàn hảo! Cảm ơn!
Anthony Brien

Hoạt động tốt cho tôi. Nhưng tôi ghét phải nhập dll như thế này: P
J4N

8
@ J4N - Không có gì sai với một chút P / Invoke thỉnh thoảng :-)
Franci Penov

1
Điều này không hiệu quả với tôi trong WPF. Nhưng sau khi chơi xung quanh, tôi tìm thấy một giải pháp dễ dàng hơn nhiều là đặt ShowInTaskbar = "False" và Visibility = "Hidden" trong XAML. Không cần pinvoke đặc biệt.
donovan

40

Bên trong lớp biểu mẫu của bạn, hãy thêm cái này:

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

        return Params;
    }
}

Nó là dễ dàng như vậy; hoạt động một sự quyến rũ!


3
Cũng cần đặt ShowInTaskbar thành false để điều này hoạt động.
Nick Spreitzer

20

Tôi đã tìm thấy một giải pháp, nhưng nó không đẹp. Cho đến nay, đây là điều duy nhất tôi đã thử thực sự hoạt động:

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

Tìm thấy nó ở đây .

Một giải pháp tổng quát hơn, có thể tái sử dụng sẽ rất hay. Tôi cho rằng bạn có thể tạo một cửa sổ duy nhất 'w' và sử dụng lại nó cho tất cả các cửa sổ trong ứng dụng của bạn cần được ẩn khỏi dấu Alt+ ↹Tab.

Cập nhật: Ok vì vậy những gì tôi đã làm là di chuyển mã trên, trừ đi this.Owner = wbit (và di chuyển w.Hide()ngay sau w.Show()đó, hoạt động tốt) vào phương thức khởi tạo của ứng dụng của tôi, tạo ra một công khai tĩnh Windowđược gọi OwnerWindow. Bất cứ khi nào tôi muốn một cửa sổ thể hiện hành vi này, tôi chỉ cần đặt this.Owner = App.OwnerWindow. Hoạt động tốt và chỉ liên quan đến việc tạo thêm một cửa sổ (và vô hình). Bạn thậm chí có thể đặt this.Owner = nullnếu bạn muốn cửa sổ xuất hiện lại trong hộp thoại Alt+ ↹Tab.

Cảm ơn Ivan Onuchin trên các diễn đàn MSDN về giải pháp.

Cập nhật 2: Bạn cũng nên ShowInTaskBar=falsebật wđể ngăn nó nhấp nháy nhanh trên thanh tác vụ khi được hiển thị.


Ngoài ra còn có một giải pháp tương tác Win32 cho vấn đề đó.
Franci Penov,

Thật thú vị, tôi đang thực hiện phương pháp này nhưng tránh cửa sổ ẩn (sử dụng cửa sổ ứng dụng chính với tư cách là chủ sở hữu) và nó không xuất hiện trong Alt-Tab ...
Dave

1
Tôi nghĩ rằng trên các cấu hình màn hình kép, màn hình thứ hai cũng có thể có tọa độ âm.
Thomas Weller

@ThomasW. Có lẽ bạn đúng. Sử dụng một offset như thế -100000có lẽ sẽ tốt hơn.
defos1

Đây thực sự là một hack tồi tệ cho vấn đề này.
Alexandru Dicu

10

Tại sao phức tạp như vậy? Thử cái này:

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

Ý tưởng lấy từ đây: http://www.csharp411.com/hide-form-from-alttab/


Làm việc cho tôi. Cảm ơn vì sự đóng góp!
MiBol

Nhưng một ToolWindow không thể được phóng to hoặc thu nhỏ. ToolWindow không phải lúc nào cũng là một lựa chọn thích hợp.
Alexandru Dicu

10

Đây là mẹo thực hiện, bất kể kiểu cửa sổ mà bạn đang cố gắng ẩn khỏi Alt+ ↹Tab.

Đặt phần sau vào hàm tạo của biểu mẫu của bạn:

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

ShowInTaskbar = false;

Form form1 = new Form ( );

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

Owner = form1;

Về cơ bản, bạn làm cho biểu mẫu của mình trở thành con của một cửa sổ vô hình có kiểu chính xác và cài đặt ShowInTaskbar để không nằm ngoài danh sách Alt-Tab. Bạn cũng phải đặt thuộc tính ShowInTaskbar của biểu mẫu của riêng bạn thành false. Hơn hết, đơn giản là biểu mẫu chính của bạn có phong cách gì không quan trọng và tất cả các điều chỉnh để thực hiện ẩn chỉ là một vài dòng trong mã khởi tạo.


Chờ đã ... ĐÂY là C # hay C hay C ++ ??? Tôi thực sự là một n00b tại gia đình C hoặc bất cứ điều gì ...
Sreenikethan tôi

3

Tại sao phải thử nhiều mã như vậy? Chỉ cần đặt FormBorderStylepropety thành FixedToolWindow. Hy vọng nó giúp.


2

xem nó: (từ 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);

Tôi sẽ thêm ở đây rằng 'Handle' có thể được yêu cầu bởi var handle = new WindowInteropHelper (this) .Handle;
Alexandru Dicu

1

Trong XAML đặt 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>

Chỉnh sửa: Điều đó vẫn hiển thị trong Alt + Tab, tôi đoán, chỉ là không có trong thanh tác vụ.


Vâng, đó là vấn đề: ShowInTaskbar không ảnh hưởng đến hộp thoại Alt + Tab, như bạn có thể mong đợi.
defos1

1

Tôi đã thử đặt khả năng hiển thị của biểu mẫu chính thành false bất cứ khi nào nó được tự động thay đổi thành true:

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

Nó hoạt động hoàn hảo :)


2
Cho đến nay, không chỉ là giải pháp dễ dàng nhất mà nó còn hoạt động rất hiệu quả đối với tôi.
Daniel McQuiston

1

nếu bạn muốn biểu mẫu không có viền, thì bạn cần thêm các câu lệnh sau vào hàm tạo của biểu mẫu:

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

VÀ bạn phải thêm phương thức sau vào lớp Biểu mẫu dẫn xuất của mình:

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

biết thêm chi tiết



0

Thuộc tính Form1:
FormBorderStyle : Sizable
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

Cá nhân tôi biết điều này là không thể thực hiện được nếu không gắn vào cửa sổ theo một cách nào đó, tôi thậm chí không chắc điều đó sẽ được thực hiện như thế nào hoặc nếu nó có thể.

Tùy thuộc vào nhu cầu của bạn, việc phát triển ngữ cảnh ứng dụng của bạn dưới dạng ứng dụng NotifyIcon (khay hệ thống) sẽ cho phép nó chạy mà không hiển thị trong ALT + TAB. TUY NHIÊN, nếu bạn mở một biểu mẫu, biểu mẫu đó sẽ vẫn tuân theo chức năng tiêu chuẩn.

Tôi có thể tìm hiểu bài viết trên blog của mình về việc tạo một ứng dụng CHỈ là NotifyIcon theo mặc định nếu bạn muốn.



Tôi đã thành thạo về NotifyIcons, cảm ơn. Vấn đề là tôi muốn ẩn các cửa sổ đang mở (không tương tác hoặc trên cùng) khỏi Alt + Tab. Thật thú vị, tôi chỉ nhận thấy rằng thanh bên của Vista không xuất hiện trong Alt + Tab, vì vậy phải có MỘT SỐ cách để làm điều đó.
defos1

Nhìn vào các bit và mảnh khác nhau, mà không thay đổi loại cửa sổ (như redbeard đã đăng), tôi không biết cách nào để làm điều này.
Người bán Mitchel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.