Reputation: 61
I came across a perculiar problem with StringBuilder and Listbox.
I made a Listbox on a WinForm and called it lbOut and a StringBuilder string named log.
The code:
public partial class formMain : Form
{
StringBuilder log = new StringBuilder();
public formMain()
{
InitializeComponent();
log.AppendLine("This is a test");
lbOut.Items.Add(log);
log.AppendLine("Second line");
}
}
If I execute this code, I should get:
This is a test
Instead I get:
This is a testSecond line
Why is that?
I mean, "Second line" isn't even add to lbOut.
I working with Visual Studio 2010, .Net 4.0 on a Vista.
Update: Thanks everyone for the answers. I've learned a bit more today.
I can't vote up (yet), but I was very pleased with the answers given.
I've forgat about the object references
Upvotes: 1
Views: 1422
Reputation: 726479
ListBox.ObjectCollection.Add
documentation provides a hint:
If the
DisplayMember
property does not have a member specified, theListBox
then calls theToString
method of the object to obtain the text to display in the list.
The call of ToString
is not happening right away, when you add the object. It happens only when ListBox
needs to render the object that you have added. It is the object, not its string
representation, that ListBox
keeps. Therefore, every time that you change the object, the text in the ListBox
is going to change.
If you do not want this to happen, you can add an immutable object, such as a string
, to your ListBox
.
Upvotes: 1
Reputation: 124
This is because you are doing it in the constructor. Internally the CLR sees the 2 log.AppendLine calls both a applied so the value of log is actually "This is a testSecond line".
If you do the exact same code in Form_Load you will get what you expect.
Upvotes: 0
Reputation: 2042
You add the log object to the list. And it gets updated by the second text change. If you want add log.toString()
to the list, then you should get what you want.
Upvotes: 0
Reputation: 156928
That happens because you pass in the StringBuilder
, and not the string
.
Hence, when it is shown in the UI, it calls ToString
on the StringBuilder
, which in the meantime has changed it's value.
A possible solution is to pass in the string
:
lbOut.Items.Add(log.ToString());
Or, even better, create a Log
method that logs the string, and adds it to the ListBox
.
Something like the method below. Note I use Invoke
if required, so the Log
method is thread safe:
private void Log(string text)
{
log.AppendLine(text);
if (lbOut.InvokeRequired)
{
lbOut.Invoke((MethodInvoker)delegate()
{
lbOut.Items.Add(text);
});
}
else
{
lbOut.Items.Add(text);
}
}
Upvotes: 2
Reputation: 3755
when you add log to lbOut you are adding a pointer to the object log not the value of log.
you would want to print/log that out before the next append or add the value of log
lbOut.Items.Add(log.ToString());
Upvotes: 0
Reputation: 62472
Your listbox has a reference to the StringBuilder
and after you added it to the listbox you updated the StringBuilder
. Just use a regular string
for this.
Upvotes: 0
Reputation: 644
But, you add log to your lbOut. Than you add something to log. It would be weird if it was not changed on your lbOut.
Upvotes: 0