// Import the GetScrollInfo function from user32.dll
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetScrollInfo(IntPtr hWnd, int n,
ref ScrollInfoStruct lpScrollInfo);
// Win32 constants
private const int SB_VERT = 1;
private const int SIF_TRACKPOS = 0x10;
private const int SIF_RANGE = 0x1;
private const int SIF_POS = 0x4;
private const int SIF_PAGE = 0x2;
private const int SIF_ALL = SIF_RANGE | SIF_PAGE |
SIF_POS | SIF_TRACKPOS;
private const int SCROLLBAR_WIDTH = 17;
private const int LISTBOX_YOFFSET = 21;
// Return structure for the GetScrollInfo method
[StructLayout(LayoutKind.Sequential)]
private struct ScrollInfoStruct
{
public int cbSize;
public int fMask;
public int nMin;
public int nMax;
public int nPage;
public int nPos;
public int nTrackPos;
}
protected override void WndProc(ref Message msg)
{
//This message code indicates the value in the list is changing
//32 is for DropDownStyle == Simple
if ((msg.Msg == 308) || (msg.Msg == 32))
{
int onScreenIndex = 0;
// Get the mouse position relative to this control
Point LocalMousePosition = this.PointToClient(Cursor.Position);
xPos = LocalMousePosition.X;
if (this.DropDownStyle == ComboBoxStyle.Simple)
{
yPos = LocalMousePosition.Y - (this.ItemHeight + 10);
}
else
{
yPos = LocalMousePosition.Y - this.Size.Height - 1;
}
// save our y position which we need to ensure the cursor is
// inside the drop down list for updating purposes
int oldYPos = yPos;
// get the 0-based index of where the cursor is on screen
// as if it were inside the listbox
while (yPos >= this.ItemHeight)
{
yPos -= this.ItemHeight;
onScreenIndex++;
}
//if (yPos < 0) { onScreenIndex = -1; }
ScrollInfoStruct si = new ScrollInfoStruct();
si.fMask = SIF_ALL;
si.cbSize = Marshal.SizeOf(si);
// msg.LParam holds the hWnd to the drop down list that appears
int getScrollInfoResult = 0;
getScrollInfoResult = GetScrollInfo(msg.LParam, SB_VERT, ref si);
// k returns 0 on error, so if there is no error add the current
// track position of the scrollbar to our index
if (getScrollInfoResult > 0)
{
onScreenIndex += si.nTrackPos;
if (this.DropDownStyle == ComboBoxStyle.Simple)
{
simpleOffset = si.nTrackPos;
}
}
// Add our offset modifier if we're a simple combobox since we don't
// continuously receive scrollbar information in this mode.
// Then make sure the item we're previewing is actually on screen.
if (this.DropDownStyle == ComboBoxStyle.Simple)
{
onScreenIndex += simpleOffset;
if (onScreenIndex > ((this.DropDownHeight /
this.ItemHeight) + simpleOffset))
{
onScreenIndex = ((this.DropDownHeight /
this.ItemHeight) + simpleOffset - 1);
}
}
// Check we're actually inside the drop down window that appears and
// not just over its scrollbar before we actually try to update anything
// then if we are raise the Hover event for this comboBox
if (!(xPos > this.Width - SCROLLBAR_WIDTH || xPos < 1 ||
oldYPos < 0 || ((oldYPos > this.ItemHeight *
this.MaxDropDownItems) && this.DropDownStyle
!= ComboBoxStyle.Simple)))
{
HoverEventArgs e = new HoverEventArgs();
e.itemIndex = (onScreenIndex > this.Items.Count - 1) ?
this.Items.Count - 1 : onScreenIndex;
OnHover(e);
// if scrollPos doesn't equal the nPos from our ScrollInfoStruct then
// the mousewheel was most likely used to scroll the drop down list
// while the mouse was inside it - this means we have to manually
// tell the drop down to repaint itself to update where it is hovering
// still posible to "outscroll" this method but it works better than
// without it present
if (scrollPos != si.nPos)
{
Cursor.Position = new Point(Cursor.Position.X +
xFactor, Cursor.Position.Y);
xFactor = -xFactor;
}
}
scrollPos = si.nPos;
}
// Pass on our message
base.WndProc(ref msg);
}
2998

被折叠的 条评论
为什么被折叠?



