当我将鼠标悬停在组合框项目上时,我无法找到要触发的事件。
我正在使用 Windows 窗体来构建应用程序。
我发现了 WPF 的类似内容:
how to change label text when I hover mouse over a combobox item? .
如何在 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;
}
最佳答案
您可以创建一个派生自 ComboBox 的自定义控件,覆盖其 WndProc拦截 CB_GETCURSEL 的方法消息。
首先调用base.WndProc(ref m)
。处理消息时,Message对象的 m.Result
属性设置为一个值(如 IntPtr
),该值表示 ListBox 中当前跟踪的 Item(当鼠标指针悬停在该 Item 上时突出显示该 Item)。
► 注意:在 .NET Framework 4.8 之前,CB_GETCURSEL
消息结果不会自动冒泡 :我们必须将LB_GETCURSEL
发送到子ListBox以获取当前突出显示的项目的索引。
使用 GetComboBoxInfo 检索 ListBox 句柄:也可以使用反射来访问它(私有(private) ChildListAutomationObject
属性返回提供句柄的 ListBox AutomationElement),或发送 CB_GETCOMBOBOXINFO
消息(但与调用 GetComboBoxInfo()
相同)。
此自定义 ComboBox 使用自定义 EventArgs
对象 ListItemSelectionChangedEventArgs
引发事件 ListItemSelectionChanged
,公开两个公共(public)属性:ItemIndex
和 ItemText
,设置为 Index 和 Text悬停的项目。
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)
=> 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. Otherwise remove
// 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 only. Otherwise remove
[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() => cbSize = Marshal.SizeOf<COMBOBOXINFO>();
}
internal static IntPtr GetComboBoxListInternal(IntPtr cboHandle)
{
var cbInfo = new COMBOBOXINFO();
cbInfo.Init();
GetComboBoxInfo(cboHandle, ref cbInfo);
return cbInfo.hwndList;
}
}
工作原理如下:
关于c# - 当我将鼠标悬停在组合框项目上时引发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61152847/