【发布时间】:2013-07-01 10:06:44
【问题描述】:
在我的应用程序中,这是一个 WF 项目,我有一个带有目录的组合框:
如果目录太大,用户将看不到整个目录名称。
现在,在大多数应用程序中,我看到如果组合框或文本框的项目超过可见限制,则在项目/鼠标位置显示/展开完整字符串(完整我的意思是目录名)
我的问题是如何做到这一点,我不知道如何使用默认工具提示来做到这一点。
更新:
我有这个用户控件,但是打开下拉列表时它变得非常慢,当悬停组合框项目时,项目之间的“导航”非常慢,就像我说的那样打开下拉列表也很慢列表后单击展开列表。
我想像默认组合框一样提高速度:
PS:我对C#一无所知
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class ComboBoxTooltip : ComboBox
{
private DropdownWindow mDropdown;
public delegate void DropdownItemSelectedEventHandler(object sender, DropdownItemSelectedEventArgs e);
public event DropdownItemSelectedEventHandler DropdownItemSelected;
protected override void OnDropDown(EventArgs e)
{
// Install wrapper
base.OnDropDown(e);
// Retrieve handle to dropdown list
COMBOBOXINFO info = new COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
SendMessageCb(this.Handle, 0x164, IntPtr.Zero, out info);
mDropdown = new DropdownWindow(this);
mDropdown.AssignHandle(info.hwndList);
}
protected override void OnDropDownClosed(EventArgs e)
{
// Remove wrapper
mDropdown.ReleaseHandle();
mDropdown = null;
base.OnDropDownClosed(e);
OnSelect(-1, Rectangle.Empty, true);
}
internal void OnSelect(int item, Rectangle pos, bool scroll)
{
if (this.DropdownItemSelected != null)
{
pos = this.RectangleToClient(pos);
DropdownItemSelected(this, new DropdownItemSelectedEventArgs(item, pos, scroll));
}
}
// Event handler arguments
public class DropdownItemSelectedEventArgs : EventArgs
{
private int mItem;
private Rectangle mPos;
private bool mScroll;
public DropdownItemSelectedEventArgs(int item, Rectangle pos, bool scroll) { mItem = item; mPos = pos; mScroll = scroll; }
public int SelectedItem { get { return mItem; } }
public Rectangle Bounds { get { return mPos; } }
public bool Scrolled { get { return mScroll; } }
}
// Wrapper for combobox dropdown list
private class DropdownWindow : NativeWindow
{
private ComboBoxTooltip mParent;
private int mItem;
public DropdownWindow(ComboBoxTooltip parent)
{
mParent = parent;
mItem = -1;
}
protected override void WndProc(ref Message m)
{
// All we're getting here is WM_MOUSEMOVE, ask list for current selection for LB_GETCURSEL
Console.WriteLine(m.ToString());
base.WndProc(ref m);
if (m.Msg == 0x200)
{
int item = (int)SendMessage(this.Handle, 0x188, IntPtr.Zero, IntPtr.Zero);
if (item != mItem)
{
mItem = item;
OnSelect(false);
}
}
if (m.Msg == 0x115)
{
// List scrolled, item position would change
OnSelect(true);
}
}
private void OnSelect(bool scroll)
{
RECT rc = new RECT();
SendMessageRc(this.Handle, 0x198, (IntPtr)mItem, out rc);
MapWindowPoints(this.Handle, IntPtr.Zero, ref rc, 2);
mParent.OnSelect(mItem, Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom), scroll);
}
}
// P/Invoke declarations
private struct COMBOBOXINFO
{
public Int32 cbSize;
public RECT rcItem;
public RECT rcButton;
public int buttonState;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
[DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessageRc(IntPtr hWnd, int msg, IntPtr wp, out RECT lp);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("user32.dll")]
private static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref RECT rc, int points);
}
【问题讨论】:
-
这是 WPF 还是(好看的)WinForm?
-
@keyboardP 对不起,我忘了评论那个大细节,是一个 WindowsForm
-
@ElektroHacker - 这似乎是一个显而易见的功能,但没有简单的属性可以处理。我还没有尝试过 David 链接中的方法,但如果它们不令人满意,NoBugz 发布了一个扩展的 ComboBox,它支持工具提示 here。 TripleDuck 和 frog297 也有更简单的建议,您可以先尝试一下。
-
@david 解决方案非常适合列表框,但有一条指令我无法为组合框重现 (Me.ListBox1.IndexFromPoint),工具提示也显示为全闪烁(工具提示每秒重新显示...)是一种令人作呕的视觉效果。我会试试你说的keyboardP
标签: .net vb.net tooltip balloon-tip