[英]How can I prevent a form from stealing focus while still receiving mouse clicks?
I'm attempting to create a custom AutoCompleteTextBox control in WinForms. 我正在尝试在WinForms中创建自定义AutoCompleteTextBox控件。 The AutoComplete provided by the basic TextBox provides results only with
(string).StartsWith
as opposed to (string).Contains
. 基本TextBox提供的AutoComplete仅提供
(string).StartsWith
而不是(string).Contains
。
I am displaying the Auto-Complete search results in a ListBox
docked in a separate Form
. 我在一个单独的
Form
停靠的ListBox
显示自动完成搜索结果。 I can prevent the Form
from stealing focus initially using via: 我可以阻止
Form
最初使用via窃取焦点:
protected override bool ShowWithoutActivation
{
get { return true; }
}
Then, I can prevent the Form
from gaining focus entirely by overriding the WndProc
method via: 然后,我可以通过覆盖
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;
}
When I do this, the ListBox
contained in the Form
will receive MouseMoved
events, but not MouseClicked
events. 当我这样做时,
Form
包含的ListBox
将接收MouseMoved
事件,但不接收MouseClicked
事件。
Chaning MA_NOACTIVATEANDEAT
to just MA_NOACTIVATE
will pass the mouse events to the ListBox
, but then will cause the clicks on the ListBox
to steal focus from the Form
the ListBox
resides in - passing it to the 'floating' Form
the ListBox
is in. Chaning
MA_NOACTIVATEANDEAT
只是MA_NOACTIVATE
将通过鼠标事件的ListBox
,但随后会导致对的点击ListBox
,从偷焦点Form
的ListBox
位于-它传递给“浮动” Form
的ListBox
在不在。
Is there any way I can prevent the 'floating' Form
from steeling focus from the 'main' Form
while still getting MouseClick
events within the ListBox
? 有没有什么办法可以阻止'浮动'
Form
从'main' Form
获得焦点,同时仍然在ListBox
获取MouseClick
事件?
Convert your floating form into a Usercontrol
as below :- Pull a ListBox on it to & hook onto Click event to simulate your scenario of Focus. 将您的浮动表单转换为
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");
}
}
}
Code in the MainForm (with a button and its click handler attached):- MainForm中的代码(附带一个按钮及其点击处理程序): -
This invokes the floating control with ListBox. 这将使用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();
}
}
}
When you show the UserControl (borderless form) as your floating form, you will notice that it wont receive focus even if you clicked (selected) any of its children
. 当您将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
。 In this case, the child is a ListBox on the usercontrol. 在这种情况下,子节点是usercontrol上的ListBox。
In addtion to previous answer by Angshuman Agarwal: If you want the main form does not deactive when the UserControl show as floating form, modify some code to your UserControl: 除了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);
}
I've created something similiar and my solution is similar to what lAbstract suggests. 我创造了类似的东西,我的解决方案与lAbstract建议的类似。 The floatin form has an event DoReturnFocus wich the custom TextBox (the AutoCompleteTextBox control in this case) subscribes to, and simply sets focus back to itself.
floatin表单有一个事件DoReturnFocus,它自定义TextBox(在这种情况下是AutoCompleteTextBox控件)订阅,并简单地将焦点设置回自身。 To prevent the main form to appear in front of the floating form I set the main form as the Owner of the floating form, as owned forms are never displayed behind their owner form..
为了防止主窗体出现在浮动窗体的前面,我将主窗体设置为浮动窗体的所有者 ,因为拥有的窗体永远不会显示在它们的所有者窗体后面。
More on Form.Owner Property 有关Form.Owner Property的更多信息
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.