2012-06-21 34 views
4

我試圖在WinForms中創建一個自定義的AutoCompleteTextBox控件。由基本TextBox提供的自動完成僅提供結果(string).StartsWith而不是(string).Contains如何防止窗體在仍然接受鼠標點擊的同時竊取焦點?

我在停靠在單獨的Form中的ListBox中顯示自動完成搜索結果。我可以通過使用防止Form從偷焦點開始:

protected override bool ShowWithoutActivation 
{ 
    get { return true; } 
} 

然後,我可以防止Form從獲得焦點完全由通過重寫WndProc方法:

protected override void WndProc(ref Message m) 
{ 
    base.WndProc(ref m); 
    switch (m.Msg) 
    { 
     case WM_MOUSEACTIVATE: 
      m.Result = (IntPtr) MA_NOACTIVATEANDEAT; 
      break; 

     default: 
      break; 
    } 

當我做到這一點, ListBox中包含的Form將收到MouseMoved事件,但不包含MouseClicked事件。

Chaning MA_NOACTIVATEANDEAT只是MA_NOACTIVATE將通過鼠標事件的ListBox,但隨後會導致對ListBox的點擊次數從Form偷焦點ListBox在於 - 它傳遞給「浮動」 FormListBox是。

有沒有什麼辦法可以防止「浮動」 Form從「主」 Form鋼化的重點,而仍然得到ListBoxMouseClick事件?

+0

我想你會簡單地被迫把在列表框中收到點擊後,焦點回到主窗體上...或者你使用鼠標移動事件,以確定哪些列表框項目正在盤旋。 HitTest(IIRC)會給你一個ListBoxItem。 – IAbstract

+0

@lAbstract移回焦點的問題在於,它會導致主窗體在下一次顯示浮動窗體時出現在浮動窗體的前面。然後在浮動窗體上調用BringToFront使其重點 - 再次從主窗體中竊取它。 – Anthony

+0

......啊,理解:所以,如果你能夠監視鼠標從你的主窗體移動,你是否能夠在你的主窗體上獲得'HitTestInfo'?如果你能做到這一點,那麼你實際上可以從浮動形式接收選定的項目......我想。 ;) – IAbstract

回答

0

將您的浮動表單轉換爲Usercontrol,如下所示: - 將其上的一個列表框勾選到&掛鉤點擊事件來模擬您的焦點場景。

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

namespace WindowsFormsApplication3 
{ 
    public partial class InactiveForm : UserControl 
    { 
     private const int WS_EX_TOOLWINDOW = 0x00000080; 
     private const int WS_EX_NOACTIVATE = 0x08000000; 
     private const int WS_EX_TOPMOST = 0x00000008; 


     [DllImport("user32")] 
     public static extern int SetParent 
     (IntPtr hWndChild, IntPtr hWndNewParent); 

     [DllImport("user32")] 
     public static extern int ShowWindow 
     (IntPtr hWnd, int nCmdShow); 


     protected override CreateParams CreateParams 
     { 
      get 
      { 

       CreateParams p = base.CreateParams; 
       p.ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST); 
       p.Parent = IntPtr.Zero; 
       return p; 
      } 
     } 

     public InactiveForm() 
     { 
      InitializeComponent(); 
     } 

     public new void Show() 
     { 
      if (this.Handle == IntPtr.Zero) base.CreateControl(); 

      SetParent(base.Handle, IntPtr.Zero); 
      ShowWindow(base.Handle, 1); 
     } 


     private void OnListBoxClicked(object sender, EventArgs e) 
     { 
      MessageBox.Show("Clicked List Box on floating control"); 

     } 
    } 
} 

代碼在MainForm的(一個按鈕和其點擊處理附後): -

這將調用與列表框浮動控制。

namespace WindowsFormsApplication3 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      InactiveForm f = new InactiveForm(); 
      f.Show(); 
     } 
    } 
} 

當你告訴用戶控件(無邊框形式)作爲浮動形式,你會發現,it wont receive focus even if you clicked (selected) any of its children。在這種情況下,該孩子是usercontrol上的ListBox。

參照herehere

0

在由Angshuman阿加瓦爾addtion到前面的答案: 如果你想在主窗體不會取消激活時,用戶控件顯示爲浮動形式,修改一些代碼到你的用戶控件:

private Control _mControl; 

[DllImport("user32.dll")] 
static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam); 

public new void Show(Control c) 
{ 
    if (c == null) throw new ArgumentNullException(); 
    _mControl = c; 
    if (this.Handle == IntPtr.Zero) base.CreateControl(); 
    SetParent(base.Handle, IntPtr.Zero); 
    ShowWindow(base.Handle, 1); 
} 

protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == 0x86) //WM_NCACTIVATE 
    { 
     if (m.WParam != IntPtr.Zero) //activate 
     { 
      SendMessage(_mControl.Handle, 0x86, (IntPtr)1, IntPtr.Zero); 
     } 
     this.DefWndProc(ref m); 
     return; 
    } 
    base.WndProc(ref m); 
} 
0

我創建的東西類似的,我的解決方案類似於摘要所暗示的。 floatin表單有一個事件DoReturnFocus,這個自定義TextBox(在這種情況下是AutoCompleteTextBox控件)訂閱並簡單地將焦點設置回自己。爲防止主表單出現在浮動表單前,我將主表單設置爲浮動表單的所有者,因爲擁有的表單永遠不會顯示在其所有者表單後面。

更多關於Form.Owner Property

相關問題