我有一个与对象集合进行数据绑定的列表框。列表框被配置为显示每个对象的标识符属性。我想显示一个工具提示,其中包含悬停在列表框中的项目的特定信息,而不是整个列表框的一个工具提示。
我正在 WinForms 中工作,感谢一些有用的博客文章,整理了一个非常好的解决方案,我想分享。
我有兴趣看看是否有任何其他优雅的解决方案来解决此问题,或者如何在 WPF 中完成此操作。
为了解决这个问题,必须解决两个主要的子问题:
- 确定鼠标悬停在哪个项目上
- 当用户将鼠标悬停在一项上,然后在列表框中移动光标并悬停在另一项上时,触发 MouseHover 事件。
第一个问题很容易解决。通过在 MouseHover 的处理程序中调用如下方法,您可以确定哪个项目正在悬停:
private ITypeOfObjectsBoundToListBox DetermineHoveredItem()
{
Point screenPosition = ListBox.MousePosition;
Point listBoxClientAreaPosition = listBox.PointToClient(screenPosition);
int hoveredIndex = listBox.IndexFromPoint(listBoxClientAreaPosition);
if (hoveredIndex != -1)
{
return listBox.Items[hoveredIndex] as ITypeOfObjectsBoundToListBox;
}
else
{
return null;
}
}
然后使用返回的值根据需要设置工具提示。
第二个问题是,通常在光标离开控件的工作区然后返回之前,不会再次触发 MouseHover 事件。
您可以通过包装来解决这个问题TrackMouseEvent
Win32API 调用。
在下面的代码中,ResetMouseHover
方法包装 API 调用以获得所需的效果:重置控制悬停事件何时触发的底层计时器。
public static class MouseInput
{
// TME_HOVER
// The caller wants hover notification. Notification is delivered as a
// WM_MOUSEHOVER message. If the caller requests hover tracking while
// hover tracking is already active, the hover timer will be reset.
private const int TME_HOVER = 0x1;
private struct TRACKMOUSEEVENT
{
// Size of the structure - calculated in the constructor
public int cbSize;
// value that we'll set to specify we want to start over Mouse Hover and get
// notification when the hover has happened
public int dwFlags;
// Handle to what's interested in the event
public IntPtr hwndTrack;
// How long it takes for a hover to occur
public int dwHoverTime;
// Setting things up specifically for a simple reset
public TRACKMOUSEEVENT(IntPtr hWnd)
{
this.cbSize = Marshal.SizeOf(typeof(TRACKMOUSEEVENT));
this.hwndTrack = hWnd;
this.dwHoverTime = SystemInformation.MouseHoverTime;
this.dwFlags = TME_HOVER;
}
}
// Declaration of the Win32API function
[DllImport("user32")]
private static extern bool TrackMouseEvent(ref TRACKMOUSEEVENT lpEventTrack);
public static void ResetMouseHover(IntPtr windowTrackingMouseHandle)
{
// Set up the parameter collection for the API call so that the appropriate
// control fires the event
TRACKMOUSEEVENT parameterBag = new TRACKMOUSEEVENT(windowTrackingMouseHandle);
// The actual API call
TrackMouseEvent(ref parameterBag);
}
}
包装到位后,您只需调用ResetMouseHover(listBox.Handle)
在 MouseHover 处理程序的末尾,即使光标停留在控件的边界内,悬停事件也会再次触发。
我确信这种将所有代码粘贴在 MouseHover 处理程序中的方法一定会导致触发比实际需要更多的 MouseHover 事件,但它会完成工作。任何改进都是非常受欢迎的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)