StringBuilder append and Listbox



我在StringBuilder和Listbox上遇到了一个明显的问题。
我在WinForm上创建了一个Listbox,并称之为lbOut和一个名为log的StringBuilder字符串。

代码:

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");
 }
}

如果我执行此代码,我应该得到:

这是个测试

相反,我得到:

这是测试第二行

为什么?
我的意思是,"第二行"甚至没有添加到lbOut中。


我在Vista上使用Visual Studio 2010,.Net 4.0。

更新:感谢大家的回答。我今天学到了更多。我(还不能投票(,但我对给出的答案非常满意。
我已经忘记了对象引用

发生这种情况是因为您传入了StringBuilder,而不是string

因此,当它显示在UI中时,它会在StringBuilder上调用ToString,同时更改了它的值。

一个可能的解决方案是传入string

lbOut.Items.Add(log.ToString());

或者,更好的是,创建一个记录字符串并将其添加到ListBoxLog方法。

类似于下面的方法。注意 如果需要,我会使用 Invoke,因此 Log 方法是线程安全的:

private void Log(string text)
{
    log.AppendLine(text);
    if (lbOut.InvokeRequired)
    {
        lbOut.Invoke((MethodInvoker)delegate()
        {
            lbOut.Items.Add(text);
        });
    }
    else
    {
        lbOut.Items.Add(text);
    }
}

ListBox.ObjectCollection.Add文档提供了一个提示:

如果 DisplayMember 属性未指定成员,则ListBox调用对象的 ToString 方法以获取要在列表中显示的文本。

添加对象时,ToString调用不会立即发生。仅当ListBox需要呈现已添加的对象时,才会发生这种情况。ListBox保留的是对象,而不是其string表示。因此,每次更改对象时,ListBox中的文本都会更改。

如果您不希望发生这种情况,则可以将不可变对象(例如string(添加到ListBox中。

但是

,您将日志添加到lbOut中。比你添加一些东西来记录。如果它没有在你的 lbOut 上改变,那就太奇怪了。

您的列表框具有对StringBuilder的引用,在将其添加到列表框后,您更新了StringBuilder。只需为此使用常规string即可。

当您将日志添加到lbOut时,您是在添加指向对象日志的指针,而不是log的值。

您可能希望在下一次追加之前打印/记录它或添加 log 的值

lbOut.Items.Add(log.ToString());

将日志对象添加到列表中。它通过第二次文本更改进行更新。如果您想将log.toString()添加到列表中,那么您应该得到您想要的。

这是因为您在构造函数中执行此操作。CLR 在内部看到 2 日志。AppendLine 调用两者 a apply,因此 log 的值实际上是"这是一个测试第二行"。

如果你在Form_Load中执行完全相同的代码,你会得到你所期望的。

最新更新