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

时间:2009-03-25 05:54:55

标签: .net combobox tooltip

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

没有像

这样的选项

combobox.items [1] .tooltip();

有没有办法添加工具提示呢?

9 个答案:

答案 0 :(得分:30)

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

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

Ye-Xin Ye,在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();
}

虽然简单明了,但这段代码确实存在一个缺陷(正如上面MSDN线程的回复中所指出的):当你将鼠标(不点击)从一个下拉项移动到下一个时,只有每个< em>其他一个显示持久的工具提示!修复只是通过该线程上的另一个条目暗示,所以我认为在这里提供完整的,更正的代码是有用的:

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 pagedownload我的开源C#库上深入查看ComboBoxWithTooltip以开始使用。 (请注意,Andrew捕获的bug的补丁将在1.1.04版本中发布,即将发布。)

答案 1 :(得分:7)

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

答案 2 :(得分:3)

我的解决方案:

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

答案 3 :(得分:1)

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

  • 它将显示与下拉列表相关联的文件的预览(在这种情况下是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();
    }
    

答案 4 :(得分:0)

您需要创建自己的UserControl

对组合框中的每个项目使用工具提示是一项不寻常的要求;也许你可以使用2列组合框来代替?

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我的解决方案:

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
}

答案 7 :(得分:0)

下面是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

答案 8 :(得分:0)

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