winform listbox drawitem изменить цвет подстроки
Я создал пользовательский элемент управления winform, который имеет текстовое поле и список, совместно использующие один и тот же источник привязки, так что список можно отфильтровать с помощью ввода текстового поля.
Мне нужно переопределить drawism для lisbox, чтобы отфильтрованные элементы, которые искали текст как подстроку, были другого цвета или выделены. (т. е.) Ожидается выделение желтого цвета, как показано на рисунке ниже.
Я сделал как ниже
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);
}
});
}
В результате текст элемента был перезаписан.
Я не могу определить часть ошибки, находится ли она в границах прямоугольника или в части на шнуровке. Кроме цвета фона элемента, как я могу изменить фон подстроки в тексте элемента. Пожалуйста помоги мне с этим.
1 ответ
Ну, задача не так проста, как следовало бы, потому что ни 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);
}
});
}