如何在聚焦时自动打开组合框?

ale*_*aro 5 .net c# combobox winforms dropdown

我有一个包含几个组合框的表单。

我希望其中一个 ComboBox 在从键盘和鼠标获得焦点时打开元素列表。

DroppedDownComboBox 类的属性管理元素列表的可见性。

最符合我需求的事件是Enter,所以我写的代码是:

private void comboBox1_Enter(object sender, EventArgs e)
{
    this.comboBox1.DroppedDown = true;
}
Run Code Online (Sandbox Code Playgroud)

它可以工作,但是当直接单击位于组合框右侧没有焦点的图标时,元素列表会打开,并且在打开后突然消失。

我尝试了很多方法来修复这种奇怪的行为,检查Focused属性或使用其他事件,如DropDownMouseClick,但没有得到任何可接受的结果。

问题的动画

Jim*_*imi 3

一种简单的方法(不会强制您覆盖ComboBox派生的 Control WndProc)是模拟HitTest,测试MouseDown是否发生在ComboBox按钮区域;然后,DroppedDown = true;仅在没有的情况下进行设置。

因此,当鼠标单击按钮时,不会产生双重效果,以意外的方式移动焦点(对于控件)。

GetComboBoxInfo()用于检索 ComboBox 按钮的正确边界,无论当前布局是(LTR 还是 RTL)。

private void comboBox1_Enter(object sender, EventArgs e)
{
    var combo = sender as ComboBox;
    if (!combo.DroppedDown) {
        var buttonRect = GetComboBoxButtonInternal(combo.Handle);
        if (!buttonRect.Contains(combo.PointToClient(Cursor.Position))) {
            combo.DroppedDown = true;
            Cursor = Cursors.Default;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

函数声明GetComboBoxInfo()

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

[StructLayout(LayoutKind.Sequential)]
internal struct COMBOBOXINFO {
    public int cbSize;
    public Rectangle rcItem;
    public Rectangle rcButton;
    public int buttonState;
    public IntPtr hwndCombo;
    public IntPtr hwndEdit;
    public IntPtr hwndList;
}

internal static Rectangle GetComboBoxButtonInternal(IntPtr cboHandle) {
    var cbInfo = new COMBOBOXINFO();
    cbInfo.cbSize = Marshal.SizeOf<COMBOBOXINFO>();
    GetComboBoxInfo(cboHandle, ref cbInfo);
    return cbInfo.rcButton;
}
Run Code Online (Sandbox Code Playgroud)