如何为列表框中的每个项目设置不同的工具提示文本?

我有一个数据绑定到对象集合的列表框。 列表框配置为显示每个对象的标识符属性。 我想展示一个工具提示,其中包含特定于列表框中正在hover的项目的信息,而不是整个列表框的一个工具提示。

我在WinForms中工作,感谢一些有用的博客文章,这是一个非常好的解决方案,我想分享。

我有兴趣看看是否有任何其他优雅的解决方案来解决这个问题,或者在WPF中如何做到这一点。

为解决这个问题,必须解决两个主要的子问题:

  1. 确定正在hover的项目
  2. 当用户hover在一个项目上时,触发MouseHover事件,然后将光标移动到列表框中并hover在另一个项目上。

第一个问题很容易解决。 通过在MouseHover的处理程序中调用类似以下的方法,您可以确定正在hover的项目:

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调用以获得所需的效果:重置控制何时触发hover事件的基础计时器。

 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); } 

}

使用包装器,只需在MouseHover处理程序的末尾调用ResetMouseHover(listBox.Handle),即使光标停留在控件的边界内,hover事件也会再次触发。

我确信这种方法,坚持MouseHover处理程序中的所有代码必须导致更多的MouseHover事件触发而不是真正必要的,但它将完成工作。 任何改进都非常受欢迎。

使用MouseMove事件,您可以跟踪鼠标所在项目的索引,并将其存储在一个变量中,该变量将其值保存在MouseMoves之间。 每次触发MouseMove时,它都会检查索引是否已更改。 如果是这样,它会禁用工具提示,更改此控件的工具提示文本,然后重新激活它。

下面是一个示例,其中Car类的单个属性显示在ListBox中,但是当鼠标hover在任何一行上时会显示完整信息。 为了使这个例子有效,你需要的只是一个名为lstCars的ListBox,它带有一个MouseMove事件和一个名为tt1的ToolTip文本组件。

汽车类的定义:

  class Car { // Main properties: public string Model { get; set; } public string Make { get; set; } public int InsuranceGroup { get; set; } public string OwnerName { get; set; } // Read only property combining all the other informaiton: public string Info { get { return string.Format("{0} {1}\nOwner: {2}\nInsurance group: {3}", Make, Model, OwnerName, InsuranceGroup); } } } 

表单加载事件:

  private void Form1_Load(object sender, System.EventArgs e) { // Set up a list of cars: List allCars = new List(); allCars.Add(new Car { Make = "Toyota", Model = "Yaris", InsuranceGroup = 6, OwnerName = "Joe Bloggs" }); allCars.Add(new Car { Make = "Mercedes", Model = "AMG", InsuranceGroup = 50, OwnerName = "Mr Rich" }); allCars.Add(new Car { Make = "Ford", Model = "Escort", InsuranceGroup = 10, OwnerName = "Fred Normal" }); // Attach the list of cars to the ListBox: lstCars.DataSource = allCars; lstCars.DisplayMember = "Model"; } 

工具提示代码(包括创建名为hoveredIndex的类级变量):

  // Class variable to keep track of which row is currently selected: int hoveredIndex = -1; private void lstCars_MouseMove(object sender, MouseEventArgs e) { // See which row is currently under the mouse: int newHoveredIndex = lstCars.IndexFromPoint(e.Location); // If the row has changed since last moving the mouse: if (hoveredIndex != newHoveredIndex) { // Change the variable for the next time we move the mouse: hoveredIndex = newHoveredIndex; // If over a row showing data (rather than blank space): if (hoveredIndex > -1) { //Set tooltip text for the row now under the mouse: tt1.Active = false; tt1.SetToolTip(lstCars, ((Car)lstCars.Items[hoveredIndex]).Info); tt1.Active = true; } } } 

我认为最好的选择,因为您将列表框数据绑定到对象,将使用datatemplate。 所以你可以这样做:

        

当然,您将使用任何绑定源替换ItemsSource绑定,并使用您实际要显示的列表中的对象的任何公共属性来绑定Path部分。 有关msdn的更多详细信息

这是一个使用ListBox创建一组RadioButton的Style。 所有都受MVVM约束。 MyClass包含两个String属性:MyName和MyToolTip。 这将显示RadioButtons列表,包括正确的ToolTip-ing。 这个线程感兴趣的是靠近底部的Setter for ToolTip,这使得它成为一个全Xaml解决方案。

用法示例:

ListBox Style =“{StaticResource radioListBox}”ItemsSource =“{Binding MyClass}”SelectedValue =“{Binding SelectedMyClass}”/>

样式:

      

使用title属性,我们可以为列表框中的每个列表项设置工具提示。

为列表框中的所有项循环。

 ListItem li = new ListItem("text","key"); li.Attributes.Add("title","tool tip text"); 

希望这可以帮助。

使用onmouseover您可以遍历列表中的每个项目,并可以显示ToolTip

 onmouseover="doTooltipProd(event,''); function doTooltipProd(e,tipObj) { Tooltip.init(); if ( typeof Tooltip == "undefined" || !Tooltip.ready ) { return; } mCounter = 1; for (m=1;m<=document.getElementById('lobProductId').length;m++) { var mCurrent = document.getElementById('lobProductId').options[m]; if(mCurrent != null && mCurrent != "null") { if (mCurrent.selected) { mText = mCurrent.text; Tooltip.show(e, mText); } } } } 

您可以使用这个在WinForms中使用ListBox的onMouseMove事件的简单代码:

 private void ListBoxOnMouseMove(object sender, MouseEventArgs mouseEventArgs) { var listbox = sender as ListBox; if (listbox == null) return; // set tool tip for listbox var strTip = string.Empty; var index = listbox.IndexFromPoint(mouseEventArgs.Location); if ((index >= 0) && (index < listbox.Items.Count)) strTip = listbox.Items[index].ToString(); if (_toolTip.GetToolTip(listbox) != strTip) { _toolTip.SetToolTip(listbox, strTip); } } 

当然,你必须在构造函数或一些init函数中初始化ToolTip对象:

 _toolTip = new ToolTip { AutoPopDelay = 5000, InitialDelay = 1000, ReshowDelay = 500, ShowAlways = true }; 

请享用!