我有一个WinForms ComboBox,可以记住之前输入的项目。我想要一种方法来删除以前的条目。我重写ComboBox的DrawItem事件以呈现文本和X图标。 X图标只是一个方形图像,我可以缩放到项目的高度。代码很简单。
// Enable the owner draw on the ComboBox.
ServerComboBox.DrawMode = DrawMode.OwnerDrawFixed;
// Handle the DrawItem event to draw the items.
ServerComboBox.DrawItem += delegate(object cmb, DrawItemEventArgs args)
{
// Draw the default background
args.DrawBackground();
String url = (String)ServerComboBox.Items[args.Index];
// Get the bounds for the first column
Rectangle r1 = args.Bounds;
r1.Width -= r1.Height;
// Draw the text
using (SolidBrush sb = new SolidBrush(args.ForeColor))
{
args.Graphics.DrawString(url, args.Font, sb, r1);
}
// Draw the X icon
Rectangle r2 = new Rectangle(r1.Width+1, r1.Y + 1, r1.Height - 2, r1.Height - 2);
args.Graphics.DrawImage(Project.Test.Properties.Resources.CloseIcon, r2);
};
现在我的问题是如何捕获是否点击了X.我的第一个想法是捕获ComboBox的MouseDown事件并检查DroppedDown属性是否为true,但是当您单击未展开的ComboBox时该事件才会被触发。如何从ComboBox的DropDown部分捕获事件。一旦我知道了,我认为找出X是否被点击或现在是一个很大的问题。
答案 0 :(得分:2)
事实上,你的问题只是Win32
可以解决的一个小问题:
public class Form1 : Form {
[DllImport("user32")]
private static extern int GetComboBoxInfo(IntPtr hwnd, out COMBOBOXINFO comboInfo);
struct RECT {
public int left, top, right, bottom;
}
struct COMBOBOXINFO {
public int cbSize;
public RECT rcItem;
public RECT rcButton;
public int stateButton;
public IntPtr hwndCombo;
public IntPtr hwndItem;
public IntPtr hwndList;
}
public Form1(){
InitializeComponent();
comboBox1.HandleCreated += (s, e) => {
COMBOBOXINFO combo = new COMBOBOXINFO();
combo.cbSize = Marshal.SizeOf(combo);
GetComboBoxInfo(comboBox1.Handle, out combo);
hwnd = combo.hwndList;
init = false;
};
}
bool init;
IntPtr hwnd;
NativeCombo nativeCombo = new NativeCombo();
//This is to store the Rectangle info of your Icons
//Key: the Item index
//Value: the Rectangle of the Icon of the item (not the Rectangle of the item)
Dictionary<int, Rectangle> dict = new Dictionary<int, Rectangle>();
public class NativeCombo : NativeWindow {
//this is custom MouseDown event to hook into later
public event MouseEventHandler MouseDown;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x201)//WM_LBUTTONDOWN = 0x201
{
int x = m.LParam.ToInt32() & 0x00ff;
int y = m.LParam.ToInt32() >> 16;
if (MouseDown != null) MouseDown(null, new MouseEventArgs(MouseButtons.Left, 1, x, y, 0));
}
base.WndProc(ref m);
}
}
//DropDown event handler of your comboBox1
private void comboBox1_DropDown(object sender, EventArgs e) {
if (!init) {
//Register the MouseDown event handler <--- THIS is WHAT you want.
nativeCombo.MouseDown += comboListMouseDown;
nativeCombo.AssignHandle(hwnd);
init = true;
}
}
//This is the MouseDown event handler to handle the clicked icon
private void comboListMouseDown(object sender, MouseEventArgs e){
foreach (var kv in dict) {
if (kv.Value.Contains(e.Location)) {
//Show the item index whose the corresponding icon was held down
MessageBox.Show(kv.Key.ToString());
return;
}
}
}
//DrawItem event handler
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e) {
//We have to save the Rectangle info of the item icons
Rectangle rect = new Rectangle(0, e.Bounds.Top, e.Bounds.Height, e.Bounds.Height);
dict[e.Index] = rect;
//Draw the icon
//e.Graphics.DrawImage(yourImage, rect);
}
}
关于会发生什么
ComboBox
附加下拉列表,可以通过Handle
访问。我们使用 GetComboBoxInfo win32 api函数来检索ComboBox
的一些信息,此信息保存在名为 COMBOBOXINFO 的结构中。我们可以通过此结构中的成员 hwndList 获取下拉列表的句柄。
访问 hwndList 后。我们可以使用自定义 NativeWindow 类(示例中的 NativeCombo )挂钩其消息循环。这允许我们轻松地干扰下拉列表的消息循环。然后我们可以捕获 WM_LBUTTONDOWN 消息来处理 MouseDown 事件。当然,它不是完整 MouseDown 事件,但它只是一个演示,在这种情况下,它足以解决问题。发送 WM_LBUTTONDOWN ,其中包含 LParam 中保存的点击的部分信息。单击的点在下拉列表的客户区的坐标中计算(不在屏幕坐标中)。我们应该注意到 DrawItem 事件处理程序还有 e.Bounds 参数,该参数也是在客户区域坐标(而不是屏幕坐标)中计算的。因此它们位于相同的坐标系中。我们使用 Rectangle.Contains 方法来了解点击的点是否包含在某些图标的边界中。我们将所有图标边界存储在字典中。那么包含点击点的 Rectangle 的相应 Key (存储 Item index )告诉我们相应的项目索引,然后我们可以进一步处理。
答案 1 :(得分:1)
当用户选择或使用鼠标滚轮SelectionIndexChanged
时,会触发事件。如果您不想对鼠标滚轮作出反应,并且如果您只需要响应点击和选择,那么您可以考虑使用SelectionChangeCommited
事件。
然后,您可以阅读SelectedIndex
或SelectedItem
属性以获取所选项目。
ListBox
的鼠标,并使用Rectange.Contains
手动检查它。将获得更多细节。
答案 2 :(得分:0)
用户点击组合框中的项目后,它将成为所选项目。您可以从组合框对象中检索此属性。
答案 3 :(得分:0)
COMBOBOXINFO 将为您提供可用于对下拉列表窗口进行子类化的信息。请参阅此示例: