Создайте событие, когда я наведу указатель мыши на элемент ComboBox - PullRequest
1 голос
/ 11 апреля 2020

Я не могу найти событие, которое возникает при наведении курсора на элементы ComboBox.
Я использую форму windows для создания приложения.
Я нашел нечто похожее для WPF:
как изменить текст метки при наведении курсора мыши на элемент комбинированного списка? .

Как сделать это аналогичным образом в Windows Формах, или есть альтернативный способ?

Класс ComboBoxListEx:

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

1 Ответ

2 голосов
/ 11 апреля 2020

Вы можете создать пользовательский элемент управления, производный от ComboBox, переопределить его WndPro c метод для перехвата сообщения CB_GETCURSEL .

Сначала позвоните base.WndProc(ref m). Когда сообщение обрабатывается, свойству m.Result объекта Message присваивается значение (например, IntPtr), которое представляет элемент, отслеживаемый в данный момент в ListBox (элемент, выделенный при наведении на него указателя мыши) ,

Примечание: до. Net Framework 4.8, результат сообщения CB_GETCURSEL не всплывает автоматически: LB_GETCUSEL должен быть отправлен на дочерний ListBox для получения индекса элемента, который в данный момент выделен .
Дескриптор ListBox извлекается с помощью GetComboBoxInfo : к нему также можно получить доступ с помощью отражения (свойство private ChildListAutomationObject возвращает элемент ListBox AutomationElement, который обеспечивает дескриптор), или отправка сообщения CB_GETCOMBOBOXINFO (но это то же самое, что вызов GetComboBoxInfo()).


Этот пользовательский ComboBox генерирует событие, ListItemSelectionChanged, с пользовательским объектом EventArgs, ListItemSelectionChangedEventArgs, который предоставляет две публикации c свойства: ItemIndex и ItemText, установите индекс и текст объекта поиска.


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 before 4.8
            // case CB_GETCURSEL can be left there or removed: it's always -1
            case 0x0134: 
                selItem = SendMessage(listBoxHandle, LB_GETCUSEL, 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 : this.GetItemText(this.Items[listItem]))
            );
        }
    }

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

    // -------------------------------------------------------------
    // .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_GETCUSEL = 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;
    }
}

Работает так:

ComboBox Custom List Hover Selection Events

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...