C# Winforms:如何使用ToolStripDropDown模拟自动关闭
我目前正在写一个组合框,我用自己的下拉列表替换建议。为此,我创建了一个ToolStripDropDown,并用列表框填充它。当用户在组合框文本字段中键入文本时,此列表框将更新 我的问题是,如果我将ToolStripDropDown的AutoClose属性设置为true,那么即使文本字段具有焦点,ToolStripDropDown似乎也会“窃取”很多消息,包括键盘消息 如果我将AutoClose属性设置为false,则一切正常。但下拉列表不会关闭,例如,如果用户在组合外部单击C# Winforms:如何使用ToolStripDropDown模拟自动关闭,c#,winforms,combobox,toolstripdropdown,C#,Winforms,Combobox,Toolstripdropdown,我目前正在写一个组合框,我用自己的下拉列表替换建议。为此,我创建了一个ToolStripDropDown,并用列表框填充它。当用户在组合框文本字段中键入文本时,此列表框将更新 我的问题是,如果我将ToolStripDropDown的AutoClose属性设置为true,那么即使文本字段具有焦点,ToolStripDropDown似乎也会“窃取”很多消息,包括键盘消息 如果我将AutoClose属性设置为false,则一切正常。但下拉列表不会关闭,例如,如果用户在组合外部单击 我想知道如何做我自己
我想知道如何做我自己的“自动关闭”,但我不知道如何实现它。你知道怎么做吗?我找到了解决办法。查看ToolStripManager代码(感谢ReSharper!),我发现当AutoClose设置为true时,manager会监视应用程序消息,以便检测用户何时单击下拉列表之外的内容。我以以下方式修改了他们的代码:
class MyComboBox : ComboBox, IMessageFilter
{
private ToolStripDropDown m_dropDown;
MyComboBox()
{
...
Application.AddMessageFilter(this);
...
}
protected override void Dispose(bool disposing)
{
...
Application.RemoveMessageFilter(this);
base.Dispose(disposing);
}
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_RBUTTONDOWN = 0x0204;
private const int WM_MBUTTONDOWN = 0x0207;
private const int WM_NCLBUTTONDOWN = 0x00A1;
private const int WM_NCRBUTTONDOWN = 0x00A4;
private const int WM_NCMBUTTONDOWN = 0x00A7;
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref Point pt, int cPoints);
public bool PreFilterMessage(ref Message m)
{
if (m_dropDown.Visible)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_NCLBUTTONDOWN:
case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN:
//
// When a mouse button is pressed, we should determine if it is within the client coordinates
// of the active dropdown. If not, we should dismiss it.
//
int i = unchecked((int)(long)m.LParam);
short x = (short)(i & 0xFFFF);
short y = (short)((i >> 16) & 0xffff);
Point pt = new Point(x, y);
MapWindowPoints(m.HWnd, m_dropDown.Handle, ref pt, 1);
if (!m_dropDown.ClientRectangle.Contains(pt))
{
// the user has clicked outside the dropdown
pt = new Point(x, y);
MapWindowPoints(m.HWnd, Handle, ref pt, 1);
if (!ClientRectangle.Contains(pt))
{
// the user has clicked outside the combo
hideDropDown();
}
}
break;
}
}
return false;
}
}
嗯,也许你也可以控制焦点,或者为你的组合框制作一个“按键预览”(就像winforms一样),我试过了,但是没有用。我还尝试捕获发送到下拉列表的所有WM_KEYDOWN、WM_keydup、WM_CHAR消息,并将它们发送回组合的编辑控件(使用SendMessage),但这也不起作用。一个非常简单但可能脏的解决方案:
ComboBox.LostFocus->Toolstripdropdown.Close()
可能起作用,但我还没有测试它。一个简单的“自动关闭”我想我已经在处理LostFocus消息了。如果我点击组合外的父窗体,我不会收到任何消息。嗯,我已经测试过它了,在这里可以工作。你有一些代码如何处理ComboBox的LostFocus?这样ToolStripManager就可以捕获消息了吗?O.oYes,在消息处理的一部分,它将所有键盘输入重定向到活动下拉菜单(ToolStripManager.PreFilterMessage->case WM_KEYDOWN:case WM_KEYUP:等)。嗨,Serge,我遇到了同样的问题,尽管我正在使用嵌入式datagridview实现自定义多列组合框。我是否有可能看到您的完整代码重新对这个自动建议窗口进行了分级?…提前感谢EverMind,我已经让它工作了,感谢您的精彩编码+从我这里得到1。