2010-05-15 33 views
5

我有一個在後臺運行的C#winforms應用程序,正在監聽要按下的熱鍵。當一個熱鍵被按下時,我的表單變成一個簡短的外觀。表單總是運行,但設置爲隱藏狀態直到我收到一個熱鍵事件,此時我將visible屬性設置爲true。代碼如下所示:如何防止我的C#winforms應用程序竊取焦點時,我將可見性設置爲true?

void hook_volumeDown(object sender, KeyPressedEventArgs e) 
{ 
    this.Visible = true; 
} 

需要注意的是,此表單的最高屬性設置爲true。

真的很奇怪的部分是,在我的C#應用​​程序從另一個應用程序中偷了焦點後,它再也不會這樣做了。例如:我啓動我的應用程序,然後啓動一些完整的應用程序,如Team Fortress 2。然後按下我的熱鍵。軍團要塞2最小化,我看到我的表格。然後,然而,我可以恢復TF2,並再次按下我的熱鍵(具有所需的效果),並且TF2將保持專注。

無論如何,我正在尋找一種解決方法。我在這裏發現了很多涉及類似問題的問題,但所有這些問題都與創建/啓動新表單有關,而不是使現有表單可見(除非我錯過了某些內容)。每次我需要時,我都可以重新編寫應用程序以創建一個新表單,但這需要創建另一種形式,以便等待熱鍵事件始終隱形,因此我寧願將其保留原樣。

任何想法?

+0

不知道我跟着...你是說它的工作原理應該*除了*第一次? – 2010-05-15 07:57:23

回答

6

我認爲你的問題與Visible = true在第一次和後續調用之間的行爲不同有關。第一次可見被調用並且窗口句柄還沒有被創建時,通過調用CreateWindowEx來創建窗口,CreateWindowEx具有一些控制窗口應該如何表現的樣式參數。我認爲你需要確保窗口是用WS_EX_NOACTIVATE風格創建的,你可以通過重寫CreateParams來完成。

其他的事情來嘗試:

1)ShowWindow函數(由可見=真使用)忽略聚焦參數在第一時間它被稱爲(http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx)如果程序提供了一個STARTUPINFO結構。挖掘反射器並找出Form類是否提供STARTUPINFO結構,如果是,則如何操作它。

2)該窗體有一個ShowWithoutActivation屬性可以被重寫並設置爲true,你重寫了這個嗎?

對不起「沒有確切的答案」,但我希望這至少給你一些進一步調查的起點。祝你好運。

+1

謝謝,重寫ShowWithoutActivation竟然是完美的解決方案。一行代碼和一切都是固定的。 – Fopedush 2010-05-15 21:26:25

+0

覆蓋ShowWithoutActivation也是我的完美解決方案。 – beppe9000 2016-05-07 11:59:05

1

看到KeyPressedEventArgs正在用於你的功能看起來確實是奇怪。熱鍵可以通過P /調用RegisterHotKey()API函數來實現。當按下熱鍵時,它會向您的窗口發送消息。下面是一個在啓動時不可見的窗體示例,當您按下熱鍵時會彈出窗體。按Ctrl + Alt + U在這種情況下:

using System; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace WindowsFormsApplication1 { 
    public partial class Form1 : Form { 
     private const int MYKEYID = 0; // In case you want to register more than one... 
     public Form1() { 
      InitializeComponent(); 
      this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID); 
     } 
     protected override void SetVisibleCore(bool value) { 
      if (value && !this.IsHandleCreated) { 
       this.CreateHandle(); 
       RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U); 
       value = false; 
      } 
      base.SetVisibleCore(value); 
     } 
     protected override void WndProc(ref Message m) { 
      if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) { 
       this.Visible = true; 
       if (this.WindowState == FormWindowState.Minimized) 
        this.WindowState = FormWindowState.Normal; 
       SetForegroundWindow(this.Handle); 
      } 
      base.WndProc(ref m); 
     } 
     // P/Invoke declarations 
     private const int WM_HOTKEY = 0x312; 
     private const int MOD_ALT = 1; 
     private const int MOD_CONTROL = 2; 
     private const int MOD_SHIFT = 4; 
     [DllImport("user32.dll")] 
     private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk); 
     [DllImport("user32.dll")] 
     private static extern bool UnregisterHotKey(IntPtr hWnd, int id); 
     [DllImport("user32.dll")] 
     private static extern bool SetForegroundWindow(IntPtr hWnd); 
    } 
} 

注意,SetForegroundWindow()函數是致命的問題,可能還有你在你的問題說明問題的根源。當用戶正在使用其他窗口時,Windows不允許應用程序在用戶的臉上推窗口。至少需要幾秒鐘的非活動時間才能讓窗口竊取焦點。使用給定的代碼,很容易看到,表單的任務欄按鈕將閃爍。避免將ShowInTaskbar屬性設置爲false。這段代碼沒有必要這麼做,直到按下熱鍵時,任務欄按鈕纔會顯示出來。

+0

Upvoting爲您的答案的徹底性,雖然我沒有嘗試它。我正在使用一個包裝類來獲取熱鍵,這些熱鍵本質上和你展示的一樣,然後觸發一個事件。爲了這個應用程序的目的,即使按下熱鍵,任務欄條目也不顯示是很重要的。 – Fopedush 2010-05-15 21:28:15

+0

我看不出如何讓你的彈出窗口丟失在更大的前景窗口後面,讓用戶無法激活它。好吧。 – 2010-05-15 21:32:38

+0

topmost設置爲true,所以除非出現異常情況(全屏應用程序),否則它將顯示。該窗口充當系統音量的OSD,我的熱鍵提升/降低/靜音。它的形式實際上只是一個無邊界的小東西,具有顯示音量%的進度條和標籤。 – Fopedush 2010-05-15 21:36:08

相關問題