如何在winforms组合框下拉列表中设置滚动位置



我在一个UI中有几个组合框,每个组合框都有一长串类似的条目(数字)。当用户从其中一个组合框中选择一个项目时,我知道用户会从其他组合框中选出一个值相似(但可能不相同)的条目。因此,在用户选择了一个值之后,为了避免强迫用户进行大量滚动,我想将下一个组合框下拉列表"自动滚动"到上一个选择值附近(当该下拉列表还没有选择时)。理想情况下,我希望滚动位置设置为最后一个选定的值显示在下拉列表的中间。

到目前为止,我已经尝试通过在下拉事件中设置所选项目来实现这一点,但这也有其自身的问题。有没有一种方法可以在不必选择项目的情况下设置下拉菜单的滚动位置?

到目前为止,我已经尝试过这个:

[DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
// P/Invoke declarations
private struct COMBOBOXINFO
{
public Int32 cbSize;
public RECT rcItem, rcButton;
public int buttonState;
public IntPtr hwndCombo, hwndEdit, hwndList;
}
private struct RECT
{
public int Left, Top, Right, Bottom;
}
private const int LVM_FIRST = 0x1000;
private const int LVM_SCROLL = (LVM_FIRST + 20);
private const int WM_VSCROLL = 0x0115;
private const int SB_BOTTOM = 7;
private const int SB_PAGEDOWN = 3;
private void comboBox_DropDown(object sender, EventArgs e)
{
COMBOBOXINFO info = new COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
SendMessageCb((sender as ComboBox).Handle, 0x164, IntPtr.Zero, out info); // seems to work
SendMessage(info.hwndList, WM_VSCROLL, (IntPtr)SB_PAGEDOWN, IntPtr.Zero); // does nothing
SendMessage(info.hwndList, LVM_SCROLL, IntPtr.Zero, (IntPtr) 50); // does nothing         
}

然而,这似乎并不奏效。COMBOBOXINFO结构似乎已正确填充,但SendMessage WM_VSCROLL和LVM_SRCROL无效。

事实证明,用WM_VSCROLL、LVM_SRCROLL发送消息(以及调用SetCrollInfo())可以设置组合框显示为下拉列表的ListView的滚动位置;问题在于DropDown事件,该事件在ListView实际显示之前就被引发了。我之所以知道这一点,是因为GetScrollInfo()在DropDown事件中调用时返回的最小值、最大值为0。从DropDown启动时起,将计时器设置为1秒延迟,并在该延迟后调用GetScrollInfo()返回合理的min,max;在该延迟之后设置滚动位置也起作用。

我显然不喜欢延迟,但我认为当ListView显示时没有可用的事件?有可能创建一些事件吗?

最新更新