.net 组合框中每个项目的工具提示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/680373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:23:24  来源:igfitidea点击:

Tooltip for each items in a combo box

.netcomboboxtooltip

提问by Michael Sorens

I just want to add a tooltip for each item in a combo box. i am using c#.net windows application.

我只想为组合框中的每个项目添加一个工具提示。我正在使用 c#.net windows 应用程序。

There is no option like

没有像

combobox.items[1].tooltip();

combobox.items[1].tooltip();

Is there any way to add tooltip it ?

有什么办法可以添加tooltip吗?

回答by Michael Sorens

There are actually a couple reasonable solutions to this question. An MSDN forum has a ComboBox Item highlight eventpost that contains two possibilities, one from nobugz and one from agrobler. Each of them provides code to subclass a ComboBox that is supposed to handle tool tips on individual items in the ComboBox's dropdown. Agrobler's solution looks more polished, in that he/she even includes some nice illustrations, but unfortunately it is not clear (at least to me) how to populate the crucial ToolTipMember property of the control.

这个问题实际上有几个合理的解决方案。MSDN 论坛有一个ComboBox 项目突出显示事件帖子,其中包含两种可能性,一种来自 nobugz,一种来自 agrobler。它们中的每一个都提供了对 ComboBox 进行子类化的代码,该 ComboBox 应该处理 ComboBox 下拉列表中各个项目的工具提示。Agrobler 的解决方案看起来更加精致,因为他/她甚至包括一些漂亮的插图,但不幸的是,不清楚(至少对我而言)如何填充控件的关键 ToolTipMember 属性。

Both of these solutions appear to allow arbitrary tooltips assigned to individual items. A more specific, but more common case, is where you simply want the tooltip to mirror the text of the item, when you know you may have items that are too long to fit the width of the ComboBox. In my own case, I have an instance of a ComboBox that holds complete file paths so it is easy to see where the contents could exceed the ComboBox's width.

这两种解决方案似乎都允许将任意工具提示分配给单个项目。一个更具体但更常见的情况是,当您知道可能有太长而无法适应 ComboBox 宽度的项目时,您只需要工具提示来反映项目的文本。在我自己的例子中,我有一个 ComboBox 的实例,它包含完整的文件路径,因此很容易看到内容可能超出 ComboBox 宽度的位置。

Zhi-Xin Ye, in the MSDN forum post Windows Dropdown question, provides a solution that addresses this more specific problem and is much simpler. I reproduce the code here in its entirety. (Note that this code presupposes you have created a Form called Form1 and hooked up the load handler shown, and also added a ComboBox named comboBox1 and a tool tip handler toolTip1.)

叶志新,在 MSDN 论坛帖子Windows Dropdown question 中,提供了解决这个更具体问题的解决方案,并且简单得多。我在这里完整地复制了代码。(请注意,此代码假定您已经创建了一个名为 Form1 的 Form 并连接了所示的加载处理程序,并且还添加了一个名为 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();
}

While simple and concise, this code does suffer from one defect (as is pointed out in a reply on the above MSDN thread): as you move the mouse (without clicking) from one dropdown item to the next, only every otherone shows a persistent tooltip! The fix is only hinted at by yet another entry on that thread, so I thought it would be useful to provide the full, corrected code here:

虽然简单明了,这个代码就从一个故障影响(如在上述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();
}

Besides removing a few redundant portions of code (e.g. the "this" qualifier) the primary difference is moving the toolTip1.Hide call into the DropDownClosed event handler. Taking it out of the DrawItem handler eliminates the defect mentioned above; but then you need to close it when the drop down closes, otherwise the last displayed tooltip will remain onscreen.

除了删除一些多余的代码部分(例如“this”限定符)之外,主要的区别是将 toolTip1.Hide 调用移动到 DropDownClosed 事件处理程序中。将其从 DrawItem 处理程序中取出,消除了上述缺陷;但是当下拉关闭时你需要关闭它,否则最后显示的工具提示将保留在屏幕上。

2012.07.31 Addendum

2012.07.31 附录

Just wanted to mention that I have since created a composite ComboBox that incorporates this tooltip capability so if you use my library you have no code to write at all. Just drag a ComboBoxWithTooltip onto the Visual Studio designer and you are done. Drill down to ComboBoxWithTooltip on my API pageor downloadmy open-source C# library to get started. (Note that the patch for the bug Andrew caught will be in release 1.1.04, due out soon.)

只想提一下,我已经创建了一个包含此工具提示功能的复合 ComboBox,因此如果您使用我的库,则根本无需编写代码。只需将 ComboBoxWithTooltip 拖到 Visual Studio 设计器上即可。深入到我的API 页面上的 ComboBoxWithTooltip或下载我的开源 C# 库以开始使用。(请注意,针对 Andrew 捕获的错误的补丁将在 1.1.04 版中发布,即将发布。)

回答by Vasu

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()) ;
}

回答by Bachor

My solution:

我的解决方案:

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);

回答by Cordell

Building upon the solution from Michael Sorens (fixed a few bugs and added features). A few things this does:

基于 Michael Sorens 的解决方案(修复了一些错误并添加了功能)。这样做有几件事情:

  • It will display a preview of a file associated with the drop down (in this case a book title from an XML file, or you can add more descriptions in the tooltip, or display something completely different).
  • It does not display tooltip for the "0" positon in the drop down (I had a placeholder, but you can simply remove the e.index>0in the second ifstatement).
  • It does not display the tooltip when the dropdown is CLOSED.

    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();
    }
    
  • 它将显示与下拉菜单相关联的文件的预览(在这种情况下是来自 XML 文件的书名,或者您可以在工具提示中添加更多描述,或显示完全不同的内容)。
  • 它不会在下拉列表中显示“0”位置的工具提示(我有一个占位符,但您可以简单地删除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();
    }
    

回答by Martin.Martinsson

My solution:

我的解决方案:

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
}

回答by nvivekgoyal

Below is c# code to show tool tip on item of combo box whose width is greater than width of combo box control. Tool tip will be shown once user hover on such combo box:

下面是 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);
            }
        }

Here is the link for more details - http://newapputil.blogspot.in/2016/12/display-tooltip-for-combo-box-item-cnet.html

这是更多详细信息的链接 - http://newapputil.blogspot.in/2016/12/display-tooltip-for-combo-box-item-cnet.html

回答by Stefan

With WPF use a ComboBox.ItemTemplate

使用 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>

回答by Mitch Wheat

You will need to create your own UserControl.

您将需要创建自己的UserControl

Having a ToolTip for each item in a combobox is an unusual requirement; perhaps you could use a 2 column combobox instead?

为组合框中的每个项目设置工具提示是一种不寻常的要求;也许您可以改用 2 列组合框?

回答by Balaji

If you are loading from a datasource, get the data into datatable and set the same to combobox. My datatable has three columns ID,NAME,DEFINITION. Below is my code :

如果您从数据源加载,请将数据放入数据表并将其设置为组合框。我的数据表有三列 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();               
        }