簡體   English   中英

如何在仍然接收鼠標點擊時阻止表單竊取焦點?

[英]How can I prevent a form from stealing focus while still receiving mouse clicks?

我正在嘗試在WinForms中創建自定義AutoCompleteTextBox控件。 基本TextBox提供的AutoComplete僅提供(string).StartsWith而不是(string).Contains

我在一個單獨的Form停靠的ListBox顯示自動完成搜索結果。 我可以阻止Form最初使用via竊取焦點:

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

然后,我可以通過覆蓋WndProc方法來阻止Form完全獲得焦點:

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

當我這樣做時, Form包含的ListBox將接收MouseMoved事件,但不接收MouseClicked事件。

Chaning MA_NOACTIVATEANDEAT只是MA_NOACTIVATE將通過鼠標事件的ListBox ,但隨后會導致對的點擊ListBox ,從偷焦點FormListBox位於-它傳遞給“浮動” FormListBox在不在。

有沒有什么辦法可以阻止'浮動' Form從'main' Form獲得焦點,同時仍然在ListBox獲取MouseClick事件?

將您的浮動表單轉換為Usercontrol ,如下所示: - 在其上拉一個ListBox以掛鈎到Click事件以模擬您的Focus場景。

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中的代碼(附帶一個按鈕及其點擊處理程序): -

這將使用ListBox調用浮動控件。

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

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

當您將UserControl(無邊框形式)顯示為浮動窗體時, it wont receive focus even if you clicked (selected) any of its children ,您也會注意到it wont receive focus even if you clicked (selected) any of its children 在這種情況下,子節點是usercontrol上的ListBox。

請參考此處此處

除了Angshuman Agarwal之前的回答之外:如果您希望當UserControl顯示為浮動窗體時主窗體不會失效,請將一些代碼修改為您的UserControl:

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

我創造了類似的東西,我的解決方案與lAbstract建議的類似。 floatin表單有一個事件DoReturnFocus,它自定義TextBox(在這種情況下是AutoCompleteTextBox控件)訂閱,並簡單地將焦點設置回自身。 為了防止主窗體出現在浮動窗體的前面,我將主窗體設置為浮動窗體的所有者 ,因為擁有的窗體永遠不會顯示在它們的所有者窗體后面。

有關Form.Owner Property的更多信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM