Mic*_*ang 20
为解决这个问题,必须解决两个主要的子问题:
第一个问题很容易解决.通过在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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用返回的值根据需要设置工具提示.
第二个问题是,通常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);
}
}
Run Code Online (Sandbox Code Playgroud)
使用包装器,只需ResetMouseHover(listBox.Handle)
在MouseHover处理程序的末尾调用,即使光标停留在控件的边界内,hover事件也会再次触发.
我确信这种方法,坚持MouseHover处理程序中的所有代码必须导致更多的MouseHover事件触发而不是真正必要的,但它将完成工作.任何改进都非常受欢迎.
Mic*_*ael 14
使用MouseMove事件,您可以跟踪鼠标所在项目的索引,并将其存储在一个变量中,该变量将其值保存在MouseMoves之间.每次触发MouseMove时,它都会检查索引是否已更改.如果是这样,它会禁用工具提示,更改此控件的工具提示文本,然后重新激活它.
下面是一个示例,其中Car类的单个属性显示在ListBox中,但是当鼠标悬停在任何一行上时会显示完整信息.为了使这个例子有用,你需要的只是一个名为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); } }
}
Run Code Online (Sandbox Code Playgroud)
表单加载事件:
private void Form1_Load(object sender, System.EventArgs e)
{
// Set up a list of cars:
List<Car> allCars = new List<Car>();
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";
}
Run Code Online (Sandbox Code Playgroud)
工具提示代码(包括创建名为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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 7
您可以使用以下简单代码,该代码使用 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);
}
}
Run Code Online (Sandbox Code Playgroud)
Of course you will have to init the ToolTip object in the constructor or some init function:
_toolTip = new ToolTip
{
AutoPopDelay = 5000,
InitialDelay = 1000,
ReshowDelay = 500,
ShowAlways = true
};
Run Code Online (Sandbox Code Playgroud)
Enjoy!
小智 6
我认为最好的选择,因为您将列表框数据绑定到对象,将使用datatemplate.所以你可以这样做:
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=TaskName}"
ToolTipService.ToolTip="{Binding Path=TaskName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
当然,您将使用任何绑定源替换ItemsSource绑定,并使用您实际要显示的列表中的对象的任何公共属性来绑定Path部分.有关msdn的更多详细信息