对C#中文本框的异步写入被覆盖
我有一个应用程序,其中两个线程异步写入单个文本框。它可以工作,除了写入文本框的第二个线程覆盖第一个线程刚刚写入的行。对这个问题的任何想法或见解都将不胜感激。我正在使用Microsoft Visual C#2008快速版。谢谢对C#中文本框的异步写入被覆盖,c#,delegates,multithreading,backgroundworker,C#,Delegates,Multithreading,Backgroundworker,我有一个应用程序,其中两个线程异步写入单个文本框。它可以工作,除了写入文本框的第二个线程覆盖第一个线程刚刚写入的行。对这个问题的任何想法或见解都将不胜感激。我正在使用Microsoft Visual C#2008快速版。谢谢 delegate void SetTextCallback(string text); private void SetText(string text) { this.textBox1.Text += text; this.textBox
delegate void SetTextCallback(string text);
private void SetText(string text)
{
this.textBox1.Text += text;
this.textBox1.Select(textBox1.Text.Length, 0);
this.textBox1.ScrollToCaret();
}
private void backgroundWorkerRx_DoWork(object sender, DoWorkEventArgs e)
{
string sText = "";
// Does some receive work and builds sText
if (textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { sText });
}
else
{
SetText(sText);
}
}
EDIT:这可能无法解决问题,但您可能希望处理BackgroundWorkers的
ProgressChanged
事件,并在那里设置文本
例如:
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
SetText((string)e.UserState);
} //Make this method handle the RunWorkerCompleted for both workers
//In DoWork:
worker.ReportProgress(0, sText);
private void AppendText(string text) {
if(textBox1.InvokeRequired) {
textBox1.Invoke(new Action<string>(AppendText), text);
return;
}
this.textBox1.AppendText(text);
this.textBox1.SelectionStart = textBox1.TextLength;
this.textBox1.ScrollToCaret();
}
ProgressChanged在UI线程上启动,因此您不需要调用Invoke
顺便说一下,您可能应该将SetText
重命名为AppendText
,以使代码更清晰。此外,您可以使用内置的委托
操作
,而不是创建自己的SetTextCallback
委托类型
编辑:此外,您可能应该将invokererequired
检查移动到SetText
例如:
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
SetText((string)e.UserState);
} //Make this method handle the RunWorkerCompleted for both workers
//In DoWork:
worker.ReportProgress(0, sText);
private void AppendText(string text) {
if(textBox1.InvokeRequired) {
textBox1.Invoke(new Action<string>(AppendText), text);
return;
}
this.textBox1.AppendText(text);
this.textBox1.SelectionStart = textBox1.TextLength;
this.textBox1.ScrollToCaret();
}
private void AppendText(字符串文本){
if(textBox1.invokererequired){
textBox1.Invoke(新操作(AppendText),text);
返回;
}
this.textBox1.AppendText(text);
this.textBox1.SelectionStart=textBox1.TextLength;
this.textBox1.ScrollToCaret();
}
尝试锁定您认为存在并发问题的代码部分
lock(someObjectUsedOnlyForLocking)
{
}
另外,尝试使用而不是手动连接字符串
this.textBox1.AppendText(text);
我同意SLaks的观点,你应该更恰当地使用BackgroundWorker。但要“修复”提供的代码,一个问题是调用。。。调用需要调用与检查需求相同的方法,以便将线程与表单的创建者对齐。我通常会做如下类似的事情(参数用法可能不可编译,但其余的都可以)。老实说,应该只需要一个处理程序,因为一次只有一个线程可以写
void backgroundWorkerTx_DoWork(object sender, DoWorkEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new EventHandler<DoWorkEventArgs>(backgroundWorkerTx_DoWork), sender, e);
return;
}
//The text you wish to set should be supplied through the event arguments
SetText((string)e.Argument);
}
void backgroundWorkerTx\u DoWork(对象发送方,DoWorkEventArgs e)
{
if(this.invokererequired)
{
this.BeginInvoke(新事件处理程序(backgroundWorkerTx_DoWork),发送方,e);
返回;
}
//要设置的文本应通过事件参数提供
SetText((字符串)e.参数);
}
您希望我们做什么?这是两个线程写入同一内容时的预期行为…是否要追加文本?SetText
函数追加文本。看起来您的代码将按编写的方式工作。可能是您在发布此消息时编辑掉的某个内容导致了错误?+1尽管可能需要锁的是SetText函数哦,而且不要傻了,在线程中使用实例锁(如果您不注意,很容易找到一个噩梦;))SetText函数只能从主线程调用,因此实际上没有什么可锁定的。他打给SetText的电话不是同时发生的。谢谢你的建议,但我的receive backgroundworker从不退出。它设置为始终运行,因为它需要接收以10毫秒间隔连续发送的消息。然后您可以调用ReportProgress
。这是正确的方法。在我看来,简单地更改SetText(或SLaks在这里将其命名为AppendText)的代码体,使invokererequired检查位于其内部就可以做到这一点。使用ReportProgress是迄今为止最整洁的解决方案,因为它不需要任何调用所需的恶作剧。然后,通过UI线程引导操作,每次文本框上只会发生一次写入。@Zoltan:他已经在UI线程上使用Invoke
调用了它。我在第二部分所做的就是移动Invoke
call.SLaks,它似乎在Textbox1中运行得非常好,现在更新得非常快,这是我拍摄的内容之一。然而,这似乎是在BackgroundWorkerRrx_DoWork开始处理数据时,就抢占了对应用程序中其他组件的控制权。这可能是由于添加到文本框中的大量数据造成的吗?