在我最近的一个项目中,我有一个组合框,其中的项目超过了组合框下拉列表的长度。我想在工具提示中显示项目的全文。不幸的是,.NET框架没有为此提供内置的解决方案。
这是我自己的解决方法
您可以在我的github上找到完整的代码,更详细的说明和示例项目。https://github.com/MaxBGitHub/MouseOverItemComboBox
[提供的代码用于C#.NET 4.5.2框架的Windows窗体库,并且是使用Visual Studio 2017编写的。
为了使它起作用,您需要利用一些本地WinAPI函数和结构。将使用以下本机函数和本机结构:
只需复制从pinvoke中粘贴的结构即可。不需要把这些缠在头上。LBItemFromPt函数和GetComboBoxInfo函数非常简单。如果您不知道如何实现这些,只需转到上面的github页面或阅读下面的代码。
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;
}
}
}
}