In my WinForms application I have a timer which ‘ticks’ every second. In the tick-method of this timer, I do various things, including adding items to a listbox (called lbxLogText).
I need to have the option to colour the text of some of the items (the colour is decided before the item is added). Because of this, I have set the DrawMode property to OwnerDrawVariable, and the lbxLogText_DrawItem method looks like this:
private void lbxLogText_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
e.Graphics.DrawString(logStringToAdd,
new Font(FontFamily.GenericSansSerif, 8),
new SolidBrush(logStringToAddColor), e.Bounds);
testCounter++;
label29.Text = testCounter.ToString();
}
logStringToAdd: a global string.
logStringToAddColor: a global Color – either red or black.
testCounter: a global int, initiated to 0.
I have a method called Log(). This is called in the tick-method of the timer mentioned above.
This is how it looks like:
private void Log(string status)
{
// |red, |black
if (status != null)
{
if (status.Contains("|red"))
{
status = status.Replace("|red", "");
logStringToAddColor = Color.Red;
}
else if (status.Contains("|black"))
{
status = status.Replace("|black", "");
logStringToAddColor = Color.Black;
}
logStringToAdd = status;
lbxLogText.Items.Add(new object());
}
// scroll to bottom
lbxLogText.SetSelected(lbxLogText.Items.Count - 1, true);
lbxLogText.SetSelected(lbxLogText.Items.Count - 1, false);
}
status: Could be “System is working correctly.|black”, or “System is NOT working correctly.|red” (for instance). This parameter is updated before the Log-call (of course).
This code works OK, to some extent. I have the following issues:
-
when running the program, I can see on
label29that thetestCountervariable is not just incremented every second, it’s like it starts at 1, then becomes 3, then 6, 10, 15, 21, 28, 36 (I think you got the pattern now). This means that the DrawItem event is called more than just every second. -
let’s say
statusgoes from “asd123|black” to “qwe456|red”. This means the next item added to the listbox should be red. Well, it does become red, but all items in the listbox become red. And the text of all items is changed to the newest as well. -
when debugging, I can see that when the
SetSelectedmethod is called, it goes right down to the DrawItem event method. But I don’t see how I can avoid this, since I need the listbox to scroll to the bottom when a new item is added, so the newest item is visible.
As Otiel said, DrawItem is called whenever any item needs to be redrawn, and you’re using a global state to store the text and colour for all of the items.
To make it specific to each item, you can add an object/type instance that returns the text as .ToString() but you can query for the colour in your DrawItem event: