I'm attempting to create a custom AutoCompleteTextBox control in WinForms. The AutoComplete provided by the basic TextBox provides results only with (string).StartsWith
as opposed to (string).Contains
.
I am displaying the Auto-Complete search results in a ListBox
docked in a separate Form
. I can prevent the Form
from stealing focus initially using via:
protected override bool ShowWithoutActivation
{
get { return true; }
}
Then, I can prevent the Form
from gaining focus entirely by overriding the WndProc
method via:
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.
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.
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
?
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.
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):-
This invokes the floating control with 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
. In this case, the child is a ListBox on the usercontrol.
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:
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. 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. 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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.