2016-04-26 3 views
0

Я создал пользовательский элемент winform, который имеет текстовое поле и список, совместно использующие один и тот же источник связывания, чтобы список можно было фильтровать с помощью ввода текстового поля.winform listbox drawitem change substring color

Мне нужно переопределить drawisem lisbox, чтобы отфильтрованные элементы искали текст в качестве подстроки, чтобы быть другого цвета или выделены. (т. е.) Ожидается желтая подсветка, например, ниже образца изображения. 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

Чтобы изменить Backgroud подстроки, я подозреваю, вы должны сначала использовать FillRectangle и затем DrawString над этим прямоугольником – Pikoh

+1

Чтобы использовать пользовательское использование BackColor TextRenderer вместо DrawString! Ваш способ продвигать прямоугольник. X использует длину строки в символах вместо пикселей. Используйте Graphics.MeasureString (... Typographics), чтобы узнать, насколько широка выделенная часть. – TaW

+0

Пробовал MeasureString с предложением FillRectangle, и я вижу разницу, но все еще нуждаюсь в небольшой настройке. Спасибо, парни. – madmonk88

ответ

2

Ну, задача не такая простая, как это должно быть, потому что ни TextRenderer.MeasureText, ни Graphics.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); 
      } 

     }); 


    } 
+0

Наконец-то !!! Я пробовал всю дорогу с помощью DrawString, но получал пробел между символами, а не в шаблоне поиска. Ваше решение находится на месте. – madmonk88

+0

Рад помочь :) – Pikoh

+0

Yup, это комбинация, которая лучше всего работает, imo. – TaW