如何从其他类和线程向ListBox添加项?(尝试代码后报错求助)
解决“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke”错误
嘿,我来帮你搞定这个问题!咱先拆解下你代码里的几个关键问题:
错误根源
- 错误创建新窗体实例:你在
Logging.add_data_to_listbox里新建了一个MainForm mnfrm = new MainForm();,这个全新的窗体根本没被显示(没调用Show()),所以它的窗口句柄还没创建,调用Invoke肯定会报错。你要操作的是已经显示的那个MainForm里的listBox1,不是新造一个空窗体。 - 线程没启动:
help_button_Click里创建了Thread但没调用t.Start(),所以add方法根本不会执行。 - 死循环占用资源:
add里的while(true)会把线程CPU占满,最好加个小延迟,避免UI卡顿。
修正后的代码
MainForm部分
partial class MainForm : Form { Logging logging= new Logging(); public MainForm() { InitializeComponent(); } private void add() { while (true) { logging.add_data_to_listbox("sometext", listBox1); // 加个小延迟,避免线程占满CPU Thread.Sleep(1000); } } private void help_button_Click(object sender, EventArgs e) { Thread t = new Thread(add); // 启动线程!之前忘了这步 t.Start(); } }
Logging类部分
public partial class Logging { public void add_data_to_listbox(string data, ListBox listbox) { // 直接用传入的listbox来判断是否需要Invoke,不用新建窗体 if (listbox.InvokeRequired) { listbox.Invoke(new MethodInvoker(delegate () { listbox.Items.Add(DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss.fff - ") + data); })); } else { // 如果已经在UI线程,直接添加 listbox.Items.Add(DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss.fff - ") + data); } } }
额外说明
- 用
listbox.InvokeRequired先判断是否需要跨线程调用,这是WinForms跨线程操作控件的标准写法。 - 死循环里的
Thread.Sleep(1000)可以根据你的需求调整间隔时间,既保证日志能持续输出,又不会让线程一直跑满CPU。 - 如果你担心线程无法停止,可以加一个布尔变量来控制循环,比如
private bool _isRunning = true;,然后在关闭窗体的时候把_isRunning设为false,循环就会退出。
内容的提问来源于stack exchange,提问作者László Bozsár
相关产品推荐
相关产品推荐

