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

时间:2012-09-29 11:18:39

标签: .net winforms combobox autoscroll

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

到目前为止,我尝试通过在下拉事件中设置所选项目来实现此目的,但是它有自己的problems。有没有办法设置下拉列表的滚动位置而无需选择项目?

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

[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_SCROLL无效。

1 个答案:

答案 0 :(得分:0)

事实证明,使用WM_VSCROLL,LVM_SCROLL(以及调用SetScrollInfo())发送消息确实可以设置ListView的滚动位置,显示为ComboBox的下拉列表;问题在于DropDown事件,它在实际显示ListView之前被引发。我认为这是因为GetScrollInfo()在DropDown事件中调用时返回min,max为0。设置一个计时器,从DropDown被触发后延迟1秒,并在该延迟后调用GetScrollInfo()返回一个合理的min,max;在延迟之后设置滚动位置也可以。

我显然不喜欢延迟,但我不认为ListView被显示时有可用的事件?是否可以创建一些活动?