我设法创建了一个简单的程序,用于从不同的线程和类更新TextBox。以可视方式学习线程的最简单方法。 ;)
代码是使用msdn的文档编写的。它运行,我看到没有内存泄漏。但我觉得这可以做得更简单。
有两个主要类别; Form和BackGround类。在BackGround类中有一个名为generateStream的函数,它通过委托给一个名为updateTextBox的函数更新Form类中的TextBox。
按下buttonStart时,会执行两个操作。首先直接调用generateStream。当generateStream准备就绪时,会生成一个再次运行generateStream的线程(通过TheFunction)。使用不同的线程时,TextBox需要一个调用解决方案。
所有这些都已实施并且有效。我认为这是相当多的代码,也许可以做得更干净。
更新表单的mainclass中的函数,并被回调。
public void updateTextBox(string strtext)
{
if (this.InvokeRequired) //When calling from another thread; invoke is required.
{
SetTextCallBack cb = new SetTextCallBack(updateTextBox);
this.Invoke(cb, new object[] { strtext });
}
else //Call can be performed safely.
{
textBoxStatus.SelectionStart = textBoxStatus.Text.Length;
textBoxStatus.AppendText(strtext);
textBoxStatus.Update();
}
}
点击按钮完成的操作。
private void buttonStart_Click(object sender, EventArgs e)
{
buttonStart.Enabled = false;
/*
* Step 1: Let's call the function blocking.
* The GUI will not respond to mouse geastures. Hoover mouse over inputbox to see no change in pointer.
*/
bg.generateStream(numberOfCalls, "GUI Thread: ");
/*
* Step 2: Let's call the function in a seperate thread.
* The GUI will now respond to the mouse. Hoover mouse over inputbox to see pointer change.
*/
Thread sepThread = new Thread(new ThreadStart(this.TheFunction));
sepThread.Start();
buttonStart.Enabled = true;
}
BackGround类中的generateStream函数。
public void generateStream(int amountOfStreams, string inpString)
{
for (int i = 0; i < amountOfStreams; i++)
{
Thread.Sleep(1000); //Easy does it.
myCallBack(inpString + i.ToString() + System.Environment.NewLine); //This is the text to the Main Form.
}
}
使用线程时,我现在使用两个回调来更新TextBox。一个从BackGround类到Form,另一个用于实现Invoke。例如,没有信号量解决方案可能我的updateTextBox函数只能有一个线程访问?
答案 0 :(得分:3)
当InvokeRequired为true时调用Invoke没有任何害处。我也喜欢在C#2.0中使用匿名方法。您可以按如下方式简化功能:
private delegate void SimpleProc();
private void updateTextBox(string strtext) {
this.Invoke(new SimpleProc(delegate() {
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.AppendText(strtext);
textBox1.Update(); // only needed if updateTextBox is called from UI thread
}), null);
}
使用BeginInvoke替换Invoke对于即发即弃方案非常有用,在这种情况下,您不希望后台线程等待UI线程完成更新,但您需要确定这是否适合您的应用
可以从UI线程或后台线程直接调用更新的函数。不需要回调;唯一使用的回调是updateTextBox中的匿名函数。它真的没有比这更简单。事实上,很简单,在很多情况下不需要创建一个单独的函数来调用UI线程。