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

z3yyvxxp  于 2022-11-16  发布在  其他
关注(0)|答案(3)|浏览(167)

我有一个包含多个组合框的窗体。
我希望其中的一个ComboBox在获得焦点时打开元素列表,无论是通过键盘还是鼠标。
ComboBox类的DroppedDown属性管理元素列表的可见性。
最符合我需要的事件是Enter,因此我编写的代码是:

private void comboBox1_Enter(object sender, EventArgs e)
{
    this.comboBox1.DroppedDown = true;
}

它工作,但当直接点击位于组合框的右侧部分的图标,没有焦点,元素列表打开,并突然消失后,它的打开。
我尝试了很多方法来修复这种奇怪的行为,检查Focused属性或使用其他事件(如DropDownMouseClick),但没有得到任何可接受的结果。

bejyjqdl

bejyjqdl1#

一种简单的方法(不强制您重写ComboBox派生控件的WndProc)是模拟 HitTest,测试 MouseDown 是否发生在ComboBox按钮区域上;那么,只有在它不存在时才设置DroppedDown = true;
因此,当鼠标单击Button时,不会产生双重效果,即以意外的方式移动Focus(对于Control)。
GetComboBoxInfo()用于检索ComboBox Button的正确边界,无论当前布局是(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;
        }
    }
}

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;
}
vqlkdk9b

vqlkdk9b2#

建立继承自ComboBox的新类别:

public class Combo : ComboBox
{
     protected override void OnClick(EventArgs e)
     {
         if (!DroppedDown) base.OnClick(e);
     }           
}

如果它没有被下拉,在它的点击中调用base.OnClick(e);。使用这个而不是组合框。(基本上,如果被下拉,点击事件将被忽略)

xeufq47z

xeufq47z3#

在表单建构函式上使用下列程式码:
this.comboBox1.GotFocus += (sender,args) => comboBox1.DroppedDown = true;

相关问题