C# 如何强制只有当用户单击下拉按钮时才能打开DropDownList样式的组合框?

C# 如何强制只有当用户单击下拉按钮时才能打开DropDownList样式的组合框?,c#,winforms,.net-2.0,combobox,C#,Winforms,.net 2.0,Combobox,在C#.NET2.0中,我有一个带有ComboBoxStyle下拉列表的WinForms组合框。但是,每当用户单击组合框上的任何位置时,都会出现下拉列表。相反,我希望只有当用户明确单击下拉按钮时它才会打开。当用户单击组合框的其余部分时,我只想将其指定为键盘焦点,这样他或她就可以对所选项目使用一些键盘命令。最好的方法是什么?您可以获得鼠标单击的X、Y位置,如果它不在下拉“图标”上,您可以从那里强制将其折叠(因为没有更好的词)

在C#.NET2.0中,我有一个带有ComboBoxStyle下拉列表的WinForms组合框。但是,每当用户单击组合框上的任何位置时,都会出现下拉列表。相反,我希望只有当用户明确单击下拉按钮时它才会打开。当用户单击组合框的其余部分时,我只想将其指定为键盘焦点,这样他或她就可以对所选项目使用一些键盘命令。最好的方法是什么?

您可以获得鼠标单击的X、Y位置,如果它不在下拉“图标”上,您可以从那里强制将其折叠(因为没有更好的词)
    void comboBox1_MouseClick(object sender, MouseEventArgs e)
    {
        ComboBox combo = sender as ComboBox;
        int left = combo.Width - (SystemInformation.HorizontalScrollBarThumbWidth + SystemInformation.HorizontalResizeBorderThickness);
        if (e.X >= left)
        {
            // They did click the button, so let it happen.
        }
        else
        {
            // They didn't click the button, so prevent the dropdown.
        }
    }
第二个问题更重要——实际上是防止出现下降。最简单的方法是:

comboBox1.DropDownStyle = ComboBoxStyle.DropDown;
但是,这允许在框中键入您可能不需要的内容

我花了大约15分钟查看选项,为了防止下拉列表出现,同时防止用户在下拉列表中键入内容,您需要对控件进行子类化。这样,您就可以重写OnMouseClick(),并且只在base.OnMouseClick()单击按钮时调用它。它看起来像这样(未经测试):


在其他答案的帮助下,我得出了以下快速解决方案:

public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        FlatStyle = FlatStyle.Popup;
        DropDownStyle = ComboBoxStyle.DropDownList;
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x0201 /* WM_LBUTTONDOWN */ || m.Msg == 0x0203 /* WM_LBUTTONDBLCLK */)
        {
            int x = m.LParam.ToInt32() & 0xFFFF;
            if (x >= Width - SystemInformation.VerticalScrollBarWidth)
                base.WndProc(ref m);
            else
            {
                Focus();
                Invalidate();
            }
        }
        else
            base.WndProc(ref m);
    }
}

滚动条的宽度很有用,但使用WinForms鼠标事件/函数没有用处。调用它们太晚。WinForms事件和函数与正常Windows消息同时调用。重要的是如何处理它们。找到一种防止默认行为的方法是一个挑战,因为时间是一样的。我写的是隐喻。在内部,似乎在调用WinForms鼠标事件之前,会出现下拉列表并发送下拉事件。因此,使用WinForms事件不足以防止出现下拉列表。
public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        FlatStyle = FlatStyle.Popup;
        DropDownStyle = ComboBoxStyle.DropDownList;
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x0201 /* WM_LBUTTONDOWN */ || m.Msg == 0x0203 /* WM_LBUTTONDBLCLK */)
        {
            int x = m.LParam.ToInt32() & 0xFFFF;
            if (x >= Width - SystemInformation.VerticalScrollBarWidth)
                base.WndProc(ref m);
            else
            {
                Focus();
                Invalidate();
            }
        }
        else
            base.WndProc(ref m);
    }
}