我是C#和GUI开发的新手。如果这是一个老问题,请直接告诉我该来源,我将删除这个问题。
我的情况:所以我正在编写一个GUI,将一个函数的控制台输出重定向到我的Windows应用程序表单中的文本框。控制台输出只向用户显示信息,如设备序列号,当前软件版本等。
我的问题:此表单效果很好,但更新软件的过程需要几分钟时间才会冻结我的表单,直到完成为止。现在,我知道实现后台工作程序可以缓解这个问题。但是,当我实现后台工作程序时,我收到以下错误。
跨线程操作无效:控制' TextBox'从创建它的线程以外的线程访问。
我的代码摘要如下:
public class Form1 : Form
{
this.backgroundWorker1.DoWork += new
System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
BigProcess(bw);
}
private void BigProcess(BackgroundWorker bw)
{
// lengthy operation that includes lots of
Console.WriteLine("feedback stuff for the user");
}
private void button1_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
}
在这个项目中,我还有一个从TextBoxStreamWriter
派生的类StringWriter
,它正在为我重定向控制台输出。在TextBoxStreamWriter
中,我重写了WriteLine
方法和Write
方法。
这是我正在做的一个例子:
public override void WriteLine(string value)
{
base.WriteLine(DateTime.Now.ToString(value));
textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
writer.Write(value);
}
调用此方法时抛出InvalidOperationException。
如何使这个线程安全?任何帮助,将不胜感激。
答案 0 :(得分:1)
您只需要将文本框的更新恢复到UI线程 - 例如:
if (textBoxOutput.InvokeRequired)
{
Invoke((MethodInvoker)(() => textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
}
else
{
textBoxOutput.AppendText(value.ToString() + Environment.NewLine)
}
答案 1 :(得分:1)
BackgroundWorker
公开一个事件:RunWorkerCompleted
,用于使用长时间运行的操作结果更新UI。该事件将在UI线程中触发。
所以你需要做的就是处理那个事件,而不是手动编组到UI线程。
backgroundWorker1.RunWorkerCompleted += (s, args)=>
textBoxOutput.AppendText(args.Result.ToString() + Environment.NewLine);
然后,您可以将DoWork
中的结果设置为您想要打印的内容。
如果要在整个后台处理过程中更新UI,则可以有效地进行“进度更新”。 BGW内置支持在整个后台工作中更新UI。有关示例,请参阅BGW的MSDN页面。
答案 2 :(得分:0)
试试这个:
public override void WriteLine(string value)
{
if (InvokeRequired)
{
Invoke(() => WriteLine(value));
return;
}
base.WriteLine(DateTime.Now.ToString(value));
textBoxOutput.AppendText(value.ToString() + Environment.NewLine);
writer.Write(value);
}
这将检查是否从与拥有表单的线程不同的线程调用WriteLine。如果是,它将要求拥有该表单的线程再次调用该方法,仅在正确的线程上。