Подсказка для каждого элемента в поле со списком

Я просто хочу добавить всплывающую подсказку для каждого элемента в поле со списком. Я использую приложение С#.net windows.

Нет такого параметра, как

combobox.items [1].tooltip();

Есть ли способ добавить всплывающую подсказку?

Ответы

Ответ 1

На самом деле есть несколько разумных решений этого вопроса. В форуме MSDN есть Сообщение об экспонировании статьи ComboBox, которое содержит две возможности, один из nobugz и один от agrobler. Каждый из них предоставляет код для подкласса ComboBox, который должен обрабатывать подсказки инструментов для отдельных элементов в выпадающем списке ComboBox. Решение Agrobler выглядит более отполированным, поскольку он даже содержит некоторые приятные иллюстрации, но, к сожалению, неясно (по крайней мере мне), как заполнить ключевое свойство ToolTipMember элемента управления.

Оба этих решения позволяют разрешить любые всплывающие подсказки, назначенные отдельным элементам. Более конкретный, но более распространенный случай - это то, где вы просто хотите, чтобы всплывающая подсказка отражала текст элемента, когда вы знаете, что у вас могут быть элементы, которые слишком длинны, чтобы соответствовать ширине ComboBox. В моем случае у меня есть экземпляр ComboBox, который содержит полные пути к файлам, поэтому легко увидеть, где содержимое может превышать ширину ComboBox.

Zhi-Xin Ye, на форуме форума MSDN вопрос о распаковке Windows, предоставляет решение, которое решает эту более конкретную проблему и намного проще. Я воспроизвожу код здесь целиком. (Обратите внимание, что этот код предполагает, что вы создали форму под названием Form1 и подключили обработчик нагрузки, а также добавили ComboBox с именем comboBox1 и 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 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, и все готово. Перейдите к ComboBoxWithTooltip на моей странице или download моя открытая библиотека С# для начала работы. (Обратите внимание, что патч для ошибки, которую Андрей поймал, будет выпущен в версии 1.1.04, вскоре должен выйти.)

Ответ 2

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

Ответ 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);

Ответ 4

Основываясь на решении Майкла Соренса (исправлено несколько ошибок и добавленных функций). Это несколько вещей:

  • Отобразится предварительный просмотр файла, связанного с выпадающим (в данном случае названием книги из файла 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();
    }
    

Ответ 5

Вам нужно будет создать собственный UserControl.

Наличие всплывающей подсказки для каждого элемента в combobox является необычным требованием; возможно, вы могли бы использовать вместо столбца 2 столбца?

Ответ 6

Если вы загружаетесь из источника данных, получите данные в datatable и установите их в combobox. У моего datatable есть три идентификатора столбца, 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();               
        }    

Ответ 7

Мое решение:

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
}

Ответ 8

Ниже приведен код С#, чтобы показать подсказку инструмента на элементе поля со списком, ширина которого больше ширины управления полем со списком. Инструмент подскажет, как только пользователь наведет на такой поле со списком:

 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

Ответ 9

С 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>