У меня есть приложение, в котором два потока асинхронно записывают в одно текстовое поле. Это работает, за исключением того, что второй поток для записи в текстовое поле перезаписывает строку, которую только что написал первый поток. Будем очень признательны за любые мысли или понимание проблемы. Я использую Microsoft Visual C # 2008 Express Edition. Спасибо.
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);
}
}
3 ответа
РЕДАКТИРОВАТЬ : это может не решить проблему, но вы можете обработать событие ProgressChanged
объекта BackgroundWorkers и установить там текст.
Например:
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);
ProgressChanged запускается в потоке пользовательского интерфейса, поэтому вам не нужно вызывать Invoke
.
Кстати, вам, вероятно, следует переименовать SetText
в AppendText
, чтобы код был понятнее.
Кроме того, вы можете использовать встроенный делегат Action<String>
вместо создания собственного типа делегата SetTextCallback
.
РЕДАКТИРОВАТЬ : вам, вероятно, следует переместить проверку InvokeRequired
на SetText
.
Например:
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();
}
ReportProgress
.
Invoke
. Все, что я сделал во второй части, это переместил вызов Invoke
.
Попробуйте заблокировать раздел кода, с которым, по вашему мнению, возникают проблемы с параллелизмом.
lock(someObjectUsedOnlyForLocking)
{
}
Кроме того, попробуйте вместо этого использовать AppendText ручного объединения строк.
this.textBox1.AppendText(text);
Я согласен с SLaks, что вам следует использовать BackgroundWorker более правильно. Но чтобы «исправить» предоставленный код, одна проблема связана с вызовом Invoke ... вызов должен вызывать тот же метод, который проверяет соответствие требованиям, что и для согласования потока с создателем формы. Обычно я делаю что-то подобное следующему (использование аргументов может быть несовместимо, но все остальное в порядке). Честно говоря, скорее всего, должен быть только один обработчик, поскольку одновременно может писать только один поток.
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);
}
Похожие вопросы
Связанные вопросы
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.
SetText
добавляет текст.