当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何为列表框中的每个项目设置不同的工具提示文本?》经验,为你挑选了3个好方法。

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

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

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



1> Michael Lang..:

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

    确定正在悬停的项目

    当用户悬停在一个项目上时,触发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事件不会再次触发,直到光标离开控件的客户区域然后再返回.

你可以通过包装TrackMouseEventWin32API调用来解决这个问题.
在以下代码中,该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处理程序的末尾调用,即使光标停留在控件的边界内,hover事件也会再次触发.

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



2> Michael..:

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

表单加载事件:

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



3> 小智..:

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


    
        
            
        
     

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


问题针对的是WinForms,而不是WPF.
推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有