winform listbox drawitem改变子串颜色
winform listbox drawitem change substring color
我创建了一个 winform 自定义控件,它有一个文本框和一个列表框,它们共享相同的绑定源,这样列表框就可以用文本框输入进行过滤。
我需要覆盖 lisbox drawitem,以便将搜索文本作为子字符串的过滤项目具有不同的颜色或突出显示。 (即,)预期黄色突出显示如下示例图像。
我做了如下操作
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);
}
});
}
结果是项目文本被字符覆盖。
我无法确定错误的部分,是在矩形边界还是在拉绳部分。除了项目背景颜色之外,如何更改项目文本中子字符串的背景。请帮我解决这个问题。
好吧,任务并不像预期的那么简单,因为 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);
}
});
}
我创建了一个 winform 自定义控件,它有一个文本框和一个列表框,它们共享相同的绑定源,这样列表框就可以用文本框输入进行过滤。
我需要覆盖 lisbox drawitem,以便将搜索文本作为子字符串的过滤项目具有不同的颜色或突出显示。 (即,)预期黄色突出显示如下示例图像。
我做了如下操作
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);
}
});
}
结果是项目文本被字符覆盖。
我无法确定错误的部分,是在矩形边界还是在拉绳部分。除了项目背景颜色之外,如何更改项目文本中子字符串的背景。请帮我解决这个问题。
好吧,任务并不像预期的那么简单,因为 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);
}
});
}