winforms 将鼠标悬停在ComboBox项上时引发事件

balp4ylt  于 2022-11-16  发布在  其他
关注(0)|答案(1)|浏览(346)

当 我 将 鼠标 悬停 在 ComboBox 项目 上 时 , 找 不到 要 激发 的 事件 。
我 正在 使用 windows 窗体 构建 一 个 应用 程序 。
我 发现 了 WPF 的 类似 内容 :
how to change label text when I hover mouse over a combobox item? 的 最 大 值 。
如何 在 Windows 窗体 中 以 类似 的 方式 执行 此 操作 , 或者 是否 有 其他 方法 ?
类 组合 框 列表 Ex :

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[DesignerCategory("Code")]
public class ComboBoxListEx : ComboBox
{
    private int listItem = -1;
    private const int CB_GETCURSEL = 0x0147;

    public event EventHandler<ListItemSelectionChangedEventArgs> ListItemSelectionChanged;

    protected virtual void OnListItemSelectionChanged(ListItemSelectionChangedEventArgs e)
        => this.ListItemSelectionChanged?.Invoke(this, e);

    public ComboBoxListEx() { }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        switch (m.Msg)
        {
            case CB_GETCURSEL:
                int selItem = m.Result.ToInt32();
                if (listItem != selItem)
                {
                    listItem = selItem;
                    OnListItemSelectionChanged(new ListItemSelectionChangedEventArgs(
                        listItem, listItem < 0 ? string.Empty : this.GetItemText(this.Items[listItem]))
                    );
                }
                break;
            default:
                // Add Case switches to handle other events
                break;
        }
    }

    public class ListItemSelectionChangedEventArgs : EventArgs
    {
        public ListItemSelectionChangedEventArgs(int idx, string text)
        {
            this.ItemIndex = idx;
            this.ItemText = text;
        }
        public int ItemIndex { get; private set; }
        public string ItemText { get; private set; }
    }
}         

private void comboBoxListEx1_ListItemSelectionChanged(object sender, ComboBoxListEx.ListItemSelectionChangedEventArgs e)
{
    label15.Text = e.ItemText;
}

中 的 每 一 个

dfty9e19

dfty9e191#

您可以建立衍生自ComboBox的Custom Control,覆写其WndProc方法以拦截CB_GETCURSEL消息。
首先调用base.WndProc(ref m)。在处理消息时,Message对象的m.Result属性将设置为一个值(IntPtr),该值表示ListBox中当前跟踪的Item(鼠标指针悬停在Item上时突出显示的Item)。
注意:.Net Framework 4.8之前,CB_GETCURSEL消息结果不会自动 * 冒泡 :我们必须将LB_GETCURSEL发送到子ListBox以获取当前 * 突出显示 * 的Item的索引。
ListBox控制代码是使用GetComboBoxInfo撷取的:也可以使用反射(私有ChildListAutomationObject属性返回ListBox AutomationElement,它提供句柄)或发送CB_GETCOMBOBOXINFO消息(但这与调用GetComboBoxInfo()相同)来访问它。
这个自订ComboBox会引发事件
*ListItemSelectionChanged,其中包含自订EventArgs对象ListItemSelectionChangedEventArgs,此对象会公开两个公用属性:ItemIndexItemText**,设置为悬停项目的索引和文本。

using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

[DesignerCategory("Code")]
public class ComboBoxListEx : ComboBox
{
    private const int CB_GETCURSEL = 0x0147;
    private int listItem = -1;
    IntPtr listBoxHandle = IntPtr.Zero;

    public event EventHandler<ListItemSelectionChangedEventArgs> ListItemSelectionChanged;

    protected virtual void OnListItemSelectionChanged(ListItemSelectionChangedEventArgs e)
        => this.ListItemSelectionChanged?.Invoke(this, e);

    public ComboBoxListEx() { }

    // .Net Framework prior to 4.8 - get the handle of the ListBox
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        listBoxHandle = GetComboBoxListInternal(this.Handle);
    }

    protected override void WndProc(ref Message m)
    {
        int selItem = -1;
        base.WndProc(ref m);

        switch (m.Msg) {
            case CB_GETCURSEL:
                selItem = m.Result.ToInt32();
                break;
            // .Net Framework prior to 4.8
            // case CB_GETCURSEL can be left there or removed: it's always -1
            case 0x0134: 
                selItem = SendMessage(listBoxHandle, LB_GETCURSEL, 0, 0);
                break;
            default:
                // Add Case switches to handle other events
                break;
        }
        if (listItem != selItem) {
            listItem = selItem;
            OnListItemSelectionChanged(new ListItemSelectionChangedEventArgs(
                listItem, listItem < 0 ? string.Empty : GetItemText(Items[listItem]))
            );
        }
    }

    public class ListItemSelectionChangedEventArgs : EventArgs
    {
        public ListItemSelectionChangedEventArgs(int idx, string text) {
            ItemIndex = idx;
            ItemText = text;
        }
        public int ItemIndex { get; private set; }
        public string ItemText { get; private set; }
    }

    // -------------------------------------------------------------
    // .Net Framework prior to 4.8
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);
    
    private const int LB_GETCURSEL = 0x0188;

    [StructLayout(LayoutKind.Sequential)]
    internal struct COMBOBOXINFO
    {
        public int cbSize;
        public Rectangle rcItem;
        public Rectangle rcButton;
        public int buttonState;
        public IntPtr hwndCombo;
        public IntPtr hwndEdit;
        public IntPtr hwndList;
        public void Init() => this.cbSize = Marshal.SizeOf<COMBOBOXINFO>();
    }

    internal static IntPtr GetComboBoxListInternal(IntPtr cboHandle)
    {
        var cbInfo = new COMBOBOXINFO();
        cbInfo.Init();
        GetComboBoxInfo(cboHandle, ref cbInfo);
        return cbInfo.hwndList;
    }
}

工作原理如下:

相关问题