Отображать всплывающую подсказку, когда элемент ComboBox превышает видимый предел?
В моем приложении, являющемся проектом WF, у меня есть комбинированный список с каталогами:
Если каталог слишком велик, пользователь не сможет увидеть полное имя каталога.
Теперь, в большинстве приложений я вижу, что если элемент комбинированного списка или текстового поля превышает видимый предел, то небольшая подсказка / ballontip отображается точно в позиции элемента / мыши, показывая / раскрывая полную строку (полное имя каталога I имею в виду)
У меня вопрос, как я могу сделать то же самое, я не знаю, как это сделать, используя подсказки по умолчанию.
ОБНОВИТЬ:
У меня есть этот пользовательский контроль, но он становится очень медленным при открытии выпадающего списка, и когда при наложении элементов комбинированного списка "навигация" между элементами очень медленная, и, как я сказал, также медленно открывается раскрывающийся список после выполнения. щелчок, чтобы расширить список.
Я хочу улучшить скорость, как по умолчанию комбинированный список:
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);
}
2 ответа
Ну, вы можете попробовать это:
Dim LastSelectedItem As Int32 = -1
Private Sub ComboBoxTooltip_DropdownItemSelected(sender As Object, e As ComboBoxTooltip.DropdownItemSelectedEventArgs) _
Handles ComboBoxTooltip1.DropdownItemSelected
Dim SelectedItem As Int32 = e.SelectedItem
If SelectedItem <> LastSelectedItem Then
ToolTip1.Hide(sender)
LastSelectedItem = -1
End If
If SelectedItem < 0 OrElse e.Scrolled Then
ToolTip1.Hide(sender)
LastSelectedItem = -1
Else
If sender.Items(e.SelectedItem).Length > CInt(sender.CreateGraphics.MeasureString(0, sender.Font).Width) + 8 Then
LastSelectedItem = SelectedItem
ToolTip1.Show(sender.Items(SelectedItem).ToString(), sender, e.Bounds.Location)
End If
End If
End Sub
И пользовательские коды управления:
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);
}
Попробуй это:
' Get the longest element
For Each elem As String In CBox1.Items
If elem.Length > auxCad.Length Then auxCad = elem
Next
' Get the size
iSize = CInt(CBox1.CreateGraphics.MeasureString(auxCad, CBox1.Font).Width) + 20
If iSize > CBox1.Width Then
'Show tooltip
End If