0

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

4

1 回答 1

0

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

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

于 2012-10-03T16:05:45.153 回答