Get ComboBox Item Index From Mouse Point

// 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);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值