我只想为组合框中的每个项目添加一个工具提示。我正在使用 c#.net windows 应用程序。
没有像
组合框.items[1].tooltip();
有什么方法可以添加tooltip吗?
这个问题实际上有几个合理的解决方案。MSDN 论坛有一个ComboBox 项目突出显示事件帖子,其中包含两种可能性,一种来自 nobugz,一种来自 agrobler。它们中的每一个都提供代码来子类化组合框,该组合框应该处理组合框下拉列表中各个项目的工具提示。Agrobler 的解决方案看起来更加精致,因为他/她甚至包括一些漂亮的插图,但不幸的是(至少对我而言)不清楚如何填充控件的关键 ToolTipMember 属性。
这两种解决方案似乎都允许将任意工具提示分配给单个项目。一个更具体但更常见的情况是,当您知道您的项目可能太长而无法适应 ComboBox 的宽度时,您只希望工具提示反映项目的文本。在我自己的情况下,我有一个包含完整文件路径的 ComboBox 实例,因此很容易看到内容可能超出 ComboBox 宽度的位置。
Zhi-Xin Ye 在 MSDN 论坛帖子Windows Dropdown question中提供了一种解决方案,可以解决这个更具体的问题,而且要简单得多。我在这里完整地复制了代码。(请注意,此代码假定您已经创建了一个名为 Form1 的表单并连接了所示的负载处理程序,还添加了一个名为 comboBox1 的 ComboBox 和一个工具提示处理程序 toolTip1。)
private void Form1_Load(object sender, EventArgs e)
{
this.comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
this.comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);
}
void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
string text = this.comboBox1.GetItemText(comboBox1.Items[e.Index]);
e.DrawBackground();
using (SolidBrush br = new SolidBrush(e.ForeColor))
{ e.Graphics.DrawString(text, e.Font, br, e.Bounds); }
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{ this.toolTip1.Show(text, comboBox1, e.Bounds.Right, e.Bounds.Bottom); }
else { this.toolTip1.Hide(comboBox1); }
e.DrawFocusRectangle();
}
虽然简单而简洁,但此代码确实存在一个缺陷(正如上述 MSDN 线程的回复中所指出的那样):当您将鼠标(不单击)从一个下拉项移动到下一项时,只有每隔一个显示持久的工具提示!该修复仅由该线程上的另一个条目暗示,因此我认为在此处提供完整的更正代码会很有用:
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
comboBox1.DrawItem += comboBox1_DrawItem;
comboBox1.DropDownClosed += comboBox1_DropDownClosed;
}
private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
toolTip1.Hide(comboBox1);
}
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0) { return; } // added this line thanks to Andrew's comment
string text = comboBox1.GetItemText(comboBox1.Items[e.Index]);
e.DrawBackground();
using (SolidBrush br = new SolidBrush(e.ForeColor))
{ e.Graphics.DrawString(text, e.Font, br, e.Bounds); }
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{ toolTip1.Show(text, comboBox1, e.Bounds.Right, e.Bounds.Bottom); }
e.DrawFocusRectangle();
}
除了删除一些冗余的代码部分(例如“this”限定符)之外,主要区别是将 toolTip1.Hide 调用移到 DropDownClosed 事件处理程序中。把它从 DrawItem 处理程序中取出,就消除了上面提到的缺陷;但是当下拉关闭时您需要关闭它,否则最后显示的工具提示将保留在屏幕上。
2012.07.31 附录
只是想提一下,我已经创建了一个包含此工具提示功能的复合 ComboBox,因此如果您使用我的库,则根本不需要编写代码。只需将 ComboBoxWithTooltip 拖到 Visual Studio 设计器上即可。深入了解我的API 页面上的 ComboBoxWithTooltip或下载我的开源 C# 库以开始使用。(请注意,Andrew 捕获的错误补丁将在 1.1.04 版中发布,即将发布。)
private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
ToolTip toolTip1 = new ToolTip();
toolTip1.AutoPopDelay = 0;
toolTip1.InitialDelay = 0;
toolTip1.ReshowDelay = 0;
toolTip1.ShowAlways = true;
toolTip1.SetToolTip(this.comboBox1, comboBox1.Items[comboBox1.SelectedIndex].ToString()) ;
}
我的解决方案:
ToolTip toolTip = new ToolTip() { AutoPopDelay = 0, InitialDelay = 0, ReshowDelay = 0, ShowAlways = true, };
comboBox.DrawMode = DrawMode.OwnerDrawFixed;
comboBox.DrawItem += (s, e) =>
{
e.DrawBackground();
string text = comboBox.GetItemText(comboBox.Items[e.Index]);
using (SolidBrush br = new SolidBrush(e.ForeColor))
e.Graphics.DrawString(text, e.Font, br, e.Bounds);
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && comboBox.DroppedDown)
toolTip.Show(text, comboBox, e.Bounds.Right, e.Bounds.Bottom + 4);
e.DrawFocusRectangle();
};
comboBox.DropDownClosed += (s, e) =>
toolTip.Hide(comboBox);
基于 Michael Sorens 的解决方案(修复了一些错误并添加了功能)。这样做的几件事:
e.index>0
第二个if
语句中的)。当下拉菜单关闭时,它不会显示工具提示。
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
ComboBox comboBox1 = (ComboBox)sender;
if (e.Index >= 0)
{//Draws all items in drop down menu
String text = comboBox1.GetItemText(comboBox1.Items[e.Index]);
e.DrawBackground();
using (SolidBrush br = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(text, e.Font, br, e.Bounds);
}
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && e.Index > 0 && comboBox1.DroppedDown)
{//Only draws tooltip when item 1+ are highlighted. I had a "--" placeholder in the 0 position
try
{
XmlDocument doc;
XmlNode testNode;
doc = new XmlDocument();
String testXMLDoc = String.Format(@"{0}\{1}.xml", filePath, fileName);//global variables
String toolTip = "---Preview of File---";
doc.Load(testXMLDoc);
testNode = doc.SelectSingleNode("/Books");
if (testNode.HasChildNodes)
{
XmlNodeList nodeList = testNode.SelectNodes("Book");
foreach (XmlNode xmlNode in nodeList)
{
toolTip += "\r\n" + xmlNode.SelectSingleNode("Title").InnerXml;
}
}
this.toolTipHelp.Show(toolTip, comboBox1, e.Bounds.Right, e.Bounds.Bottom);
}
catch (Exception tp)
{
Debug.WriteLine("Error in comboBox1 tooltip: " + tp);
}
}
else
{
this.toolTipHelp.Hide(comboBox1);
}
}
else
{
this.toolTipHelp.Hide(comboBox1);
}
e.DrawFocusRectangle();
}
您将需要创建自己的UserControl。
组合框中的每个项目都有一个工具提示是一个不寻常的要求。也许您可以改用 2 列组合框?
如果您从数据源加载,请将数据放入数据表并将其设置为组合框。我的数据表有三列 ID、NAME、DEFINITION。下面是我的代码:
InputQuery = "select * from ds_static_frequency";
TempTable = UseFunc.GetData(InputQuery);
cmbxUpdateFrequency.DataSource = TempTable;
cmbxUpdateFrequency.DataTextField = "NAME";
cmbxUpdateFrequency.DataValueField = "ID";
cmbxUpdateFrequency.DataBind();
foreach (DataRow dr in TempTable.Rows)
{
int CurrentRow = Convert.ToInt32(dr["ID"].ToString());
cmbxUpdateFrequency.Items[CurrentRow - 1].ToolTip = dr["Definition"].ToString();
}
使用 WPF 使用 ComboBox.ItemTemplate
<ComboBox
ItemsSource="{Binding Path=ComboBoxItemViewModels}"
SelectedValue="{Binding SelectedComboBoxItem,
SelectedValuePath="Name"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" ToolTip="{Binding Path=Description}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
我的解决方案:
public class ToolTipComboBox: ComboBox
{
#region Fields
private ToolTip toolTip;
private bool _tooltipVisible;
private bool _dropDownOpen;
#endregion
#region Types
[StructLayout(LayoutKind.Sequential)]
// ReSharper disable once InconsistentNaming
public struct COMBOBOXINFO
{
public Int32 cbSize;
public RECT rcItem;
public RECT rcButton;
public ComboBoxButtonState buttonState;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
}
public enum ComboBoxButtonState
{
// ReSharper disable once UnusedMember.Global
StateSystemNone = 0,
// ReSharper disable once UnusedMember.Global
StateSystemInvisible = 0x00008000,
// ReSharper disable once UnusedMember.Global
StateSystemPressed = 0x00000008
}
[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
#endregion
#region Properties
private IntPtr HwndCombo
{
get
{
COMBOBOXINFO pcbi = new COMBOBOXINFO();
pcbi.cbSize = Marshal.SizeOf(pcbi);
GetComboBoxInfo(Handle, ref pcbi);
return pcbi.hwndCombo;
}
}
private IntPtr HwndDropDown
{
get
{
COMBOBOXINFO pcbi = new COMBOBOXINFO();
pcbi.cbSize = Marshal.SizeOf(pcbi);
GetComboBoxInfo(Handle, ref pcbi);
return pcbi.hwndList;
}
}
[Browsable(false)]
public new DrawMode DrawMode
{
get { return base.DrawMode; }
set { base.DrawMode = value; }
}
#endregion
#region ctor
public ToolTipComboBox()
{
toolTip = new ToolTip
{
UseAnimation = false,
UseFading = false
};
base.DrawMode = DrawMode.OwnerDrawFixed;
DrawItem += OnDrawItem;
DropDownClosed += OnDropDownClosed;
DropDown += OnDropDown;
MouseLeave += OnMouseLeave;
}
#endregion
#region Methods
private void OnDropDown(object sender, EventArgs e)
{
_dropDownOpen = true;
}
private void OnMouseLeave(object sender, EventArgs e)
{
ResetToolTip();
}
private void ShowToolTip(string text, int x, int y)
{
toolTip.Show(text, this, x, y);
_tooltipVisible = true;
}
private void OnDrawItem(object sender, DrawItemEventArgs e)
{
ComboBox cbo = sender as ComboBox;
if (e.Index == -1) return;
// ReSharper disable once PossibleNullReferenceException
string text = cbo.GetItemText(cbo.Items[e.Index]);
e.DrawBackground();
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
TextRenderer.DrawText(e.Graphics, text, e.Font, e.Bounds.Location, SystemColors.Window);
if (_dropDownOpen)
{
Size szText = TextRenderer.MeasureText(text, cbo.Font);
if (szText.Width > cbo.Width - SystemInformation.VerticalScrollBarWidth && !_tooltipVisible)
{
RECT rcDropDown;
GetWindowRect(HwndDropDown, out rcDropDown);
RECT rcCombo;
GetWindowRect(HwndCombo, out rcCombo);
if (rcCombo.Top > rcDropDown.Top)
{
ShowToolTip(text, e.Bounds.X, e.Bounds.Y - rcDropDown.Rect.Height - cbo.ItemHeight - 5);
}
else
{
ShowToolTip(text, e.Bounds.X, e.Bounds.Y + cbo.ItemHeight - cbo.ItemHeight);
}
}
}
}
else
{
ResetToolTip();
TextRenderer.DrawText(e.Graphics, text, e.Font, e.Bounds.Location, cbo.ForeColor);
}
e.DrawFocusRectangle();
}
private void OnDropDownClosed(object sender, EventArgs e)
{
_dropDownOpen = false;
ResetToolTip();
}
private void ResetToolTip()
{
if (_tooltipVisible)
{
// ReSharper disable once AssignNullToNotNullAttribute
toolTip.SetToolTip(this, null);
_tooltipVisible = false;
}
}
#endregion
}
下面是 C# 代码,用于在宽度大于组合框控件宽度的组合框项目上显示工具提示。一旦用户将鼠标悬停在此类组合框上,将显示工具提示:
this.combo_box1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.combo_box1.DrawMode = DrawMode.OwnerDrawFixed;
this.combo_box1.DrawItem += new DrawItemEventHandler(combo_box1_DrawItem);
this.combo_box1.DropDownClosed += new EventHandler(combo_box1_DropDownClosed);
this.combo_box1.MouseLeave += new EventHandler(combo_box1_Leave);
void combo_box1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0) { return; }
string text = combo_box1.GetItemText(combo_box1.Items[e.Index]);
e.DrawBackground();
using (SolidBrush br = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(text, e.Font, br, e.Bounds);
}
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected && combo_box1.DroppedDown)
{
if (TextRenderer.MeasureText(text, combo_box1.Font).Width > combo_box1.Width)
{
toolTip1.Show(text, combo_box1, e.Bounds.Right, e.Bounds.Bottom);
}
else
{
toolTip1.Hide(combo_box1);
}
}
e.DrawFocusRectangle();
}
private void combo_box1_DropDownClosed(object sender, EventArgs e)
{
toolTip1.Hide(combo_box1);
}
private void combo_box1_Leave(object sender, EventArgs e)
{
toolTip1.Hide(combo_box1);
}
private void combo_box1_MouseHover(object sender, EventArgs e)
{
if (!combo_box1.DroppedDown && TextRenderer.MeasureText(combo_box1.SelectedItem.ToString(), combo_box1.Font).Width > combo_box1.Width)
{
toolTip1.Show(combo_box1.SelectedItem.ToString(), combo_box1, combo_box1.Location.X, combo_box1.Location.Y);
}
}
这是更多详细信息的链接 - http://newapputil.blogspot.in/2016/12/display-tooltip-for-combo-box-item-cnet.html