winform listbox drawitem更改子字符串颜色

时间:2016-04-26 08:13:04

标签: c# winforms listbox ondrawitem

我创建了一个winform自定义控件,其文本框和列表框都共享相同的bindingsource,因此可以使用文本框输入过滤列表框。

我需要覆盖lisbox drawitem,以便将已搜索文本作为子字符串的已过滤项目具有不同的颜色或突出显示。 (即,)预期黄色高光如下图样品。 sample reference

我做了如下

private void DrawItemHandler(object sender, DrawItemEventArgs e)
        {
            this.Invoke((MethodInvoker)delegate
            {
                e.DrawBackground();
                e.DrawFocusRectangle();

                string MyString = listBox.GetItemText(listBox.Items[e.Index]);
                string stringToFind = searchInput.Text ;

                if (!string.IsNullOrEmpty(stringToFind))
                {
                    List<int> positions = new List<int>();
                    int pos = 0;
                    while ((pos < MyString.Length) && (pos = MyString.IndexOf(stringToFind, pos, StringComparison.InvariantCultureIgnoreCase)) != -1)
                    {
                        positions.Add(pos);
                        pos += stringToFind.Length;
                    }

                    int c = 0, nLen = 0, width = 0;
                    Rectangle rect = e.Bounds;
                    rect.X = width;
                    do
                    {
                        if (positions.Contains(c))
                        {
                            //int opacity = 128;
                            e.Graphics.DrawString(MyString.Substring(c, stringToFind.Length),
                                                    e.Font,
                                //new SolidBrush(Color.FromArgb(opacity, Color.LightYellow)),
                                                    new SolidBrush(Color.LightYellow),
                                                    rect);
                            nLen = MyString.Substring(c, stringToFind.Length).Length;
                            width += nLen;
                        }
                        else
                        {
                            e.Graphics.DrawString(MyString[c].ToString(),
                            e.Font,
                            new SolidBrush(listBox.ForeColor),
                            rect);
                            nLen = MyString[c].ToString().Length;
                            width += nLen;
                        }
                        rect.X = width;
                    }
                    while ((c += nLen) < MyString.Length);
                }
                else
                {
                    e.Graphics.DrawString(MyString,
                        e.Font,
                        new SolidBrush(listBox.ForeColor),
                        e.Bounds);
                }

            });

        }

结果是项目文本被覆盖了字符。

initially after search

我无法识别错误部分,是在矩形边界还是拉绳部分。除了项目背景颜色外,如何更改项目文本中子字符串的背景。请帮帮我。

1 个答案:

答案 0 :(得分:2)

嗯,这项任务并不容易,因为TextRenderer.MeasureTextGraphics.MeasureString似乎都不是很准确。但是使用Graphics.MeasureString的不同重载传递矩形宽度和StringFormat.GenericTypographic它似乎工作得更好。

这是我对你的问题的尝试,希望它有所帮助:

    private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        ListBox listBox = (ListBox)sender;
        this.Invoke((MethodInvoker)delegate
        {
            e.DrawBackground();
            e.DrawFocusRectangle();

            string MyString = listBox.GetItemText(listBox.Items[e.Index]);
            string stringToFind = searchInput.Text;


            if (!string.IsNullOrEmpty(stringToFind))
            {
                string[] strings = MyString.Split(new string[] { stringToFind }, StringSplitOptions.None);

                Rectangle rect = e.Bounds;

                for (int i=0;i<strings.Length;i++)
                {
                    string s = strings[i];
                    if (s != "")
                    {
                        int width = (int)e.Graphics.MeasureString(s, e.Font,e.Bounds.Width, StringFormat.GenericTypographic).Width;
                        rect.Width = width;
                        TextRenderer.DrawText(e.Graphics, s, e.Font, new Point(rect.X, rect.Y), listBox.ForeColor);
                        rect.X += width;
                    }

                    if (i < strings.Length - 1)
                    {
                        int width2 = (int)e.Graphics.MeasureString(stringToFind, e.Font, e.Bounds.Width, StringFormat.GenericTypographic).Width;
                        rect.Width = width2;
                        TextRenderer.DrawText(e.Graphics, stringToFind, e.Font, new Point(rect.X, rect.Y), listBox.ForeColor, Color.Yellow);
                        rect.X += width2;
                    }
                }
            }
            else
            {
                TextRenderer.DrawText(e.Graphics, MyString, e.Font, new Point(e.Bounds.X, e.Bounds.Y), listBox.ForeColor);
            }

        });


    }