C#Windows窗体-如何获取光标下方的组合框项目的索引

问题描述 投票:1回答:1

在我最近的一个项目中,我有一个组合框,其中的项目超过了组合框下拉列表的长度。我想在工具提示中显示项目的全文。不幸的是,.NET框架没有为此提供内置的解决方案。

c# winforms drop-down-menu combobox mouseover
1个回答
0
投票

这是我自己的解决方法

您可以在我的github上找到完整的代码,更详细的说明和示例项目。https://github.com/MaxBGitHub/MouseOverItemComboBox

先决条件

[提供的代码用于C#.NET 4.5.2框架的Windows窗体库,并且是使用Visual Studio 2017编写的。

为了使它起作用,您需要利用一些本地WinAPI函数和结构。将使用以下本机函数和本机结构:

只需复制从pinvoke中粘贴的结构即可。不需要把这些缠在头上。LBItemFromPt函数和GetComboBoxInfo函数非常简单。如果您不知道如何实现这些,只需转到上面的github页面或阅读下面的代码。

自定义ComboBox类实现

using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
using System;


class MouseOverItemComboBox : ComboBox
{
    // Event delegate
    public delegate void OnMouseOverItem(object sender, MouseOverEventArgs e);
    // Event which the parent can subscribe to.
    public event OnMouseOverItem MouseOverItem;

    // The possible combo box button states.
    enum ButtonState {
        STATE_SYSTEM_NONE       = 0,            // Button exists and is not pressed.
        STATE_SYSTEM_INVISIBLE  = 0x00008000,   // There is no button.
        STATE_SYSTEM_PRESSED    = 0x00000008,   // Button is pressed.
    }

    /* Native COMBOBOXINFO struct implementation.
    ** Contains combo box status information. */
    [StructLayout(LayoutKind.Sequential)]
    struct COMBOBOXINFO
    {
        public int          cbSize;         // Size in bytes of struct.
        public RECT         rcItem;         // RECT that specifies the coordinates of the edit box.
        public RECT         rcButton;       // RECT that specifies the coordinates of the drop-down button.
        public ButtonState  stateButton;    // Drop-down button state.
        public IntPtr       hwndCombo;      // Handle to the combo box.
        public IntPtr       hwndEdit;       // Handle to the edit box.
        public IntPtr       hwndList;       // Handle to the drop-down list.
    }


    /* Sent to parent window of a list box before the system draws the list box.
    ** Can set text and background color of the list box by using the specified
    ** device context handle. */
    const int WM_CTLCOLORLISTBOX = 0x0134;


    // Native function that retreives information about the specified combo box.
    // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcomboboxinfo
    [DllImport("user32.dll", SetLastError = true)]
    static extern bool GetComboBoxInfo(IntPtr hWnd, [In][Out] ref COMBOBOXINFO pcbi);

    // Native function that retreives the index of the item at the specified point in a list box.
    // https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-lbitemfrompt
    [DllImport("Comctl32.dll", SetLastError = true)]
    static extern int LBItemFromPt(IntPtr hLB, POINT pt, bool bAutoScroll);


    // Helper method which will invoke the MouseOverItem event.
    private void HandleMouseOverItem()
    {
        // cbSize must be set before calling GetComboBoxInfo.
        COMBOBOXINFO pcbi = new COMBOBOXINFO();         
        pcbi.cbSize = Marshal.SizeOf(pcbi);

        // Get combo box information.
        GetComboBoxInfo(Handle, ref pcbi);
        // Check for invalid pointer... just in case.
        if (pcbi.hwndList == IntPtr.Zero)
            return;

        // Current position of cursor.
        POINT pt = Cursor.Position;
        // LBItemFromPt will return the Index of the Item on success.
        int retVal = LBItemFromPt(pcbi.hwndList, pt, false);
        if (retVal == -1)
            return;

        // Invoke the event.
        MouseOverItem?.Invoke(this, new MouseOverEventArgs(retVal));
    }


    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            /* This message is sent by the list box of the combo box.
            ** It is sent before the system draws the list box.
            ** Whenever the cursor enters a list item this message will be
            ** sent to the parent i.e. the combox box.
            ** NOTE that this message is always sent twice.
            ** First time for drawing the default item background.
            ** Second time for drawing the highlighted item background. */
            case WM_CTLCOLORLISTBOX:
                {
                    // Let the helper method do the rest.
                    HandleMouseOverItem();
                    base.WndProc(ref m);
                    break;
                }
            default:
                {
                    base.WndProc(ref m);
                    break;
                }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.