我们都知道如何在多线程环境下面调用外部控件方法会造成跨线程异常,而常用的方法为设置系统去忽略这个错误,这是比较错误的做法。今天就来学习下如何去安全的跨线程调用外部控件方法。
首先我们使用RichTextBox作为示例,正常情况下面RichTextBox的AppendText添加显示数据不会出现异常,而在多线程情况下面就会出现错误提示。这时候我们就需要定义一个用于多线程情况下进行AppendText的方法。
void WriteLog(Color color, string text, params object[] param)
{
if (!this.rtbx_system_log.InvokeRequired)
{
this.rtbx_system_log.ScrollToCaret();
this.rtbx_system_log.SelectionColor = color;
this.rtbx_system_log.AppendText(string.Format("{0}:{1}\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format(text, param)));
}
else
{
delWriteLog log = new delWriteLog(WriteLog);
this.rtbx_system_log.Invoke(log, new object[] { color, text, param });
}
}
1、首先我们需要判断是主线程还是其他线程调用的此方法
!this.rtbx_system_log.InvokeRequired
否则表示为主线程调用此方法,则可以直接添加数据,因为这个控件是由主线程创建的,故主线程拥有对他的直接操作权。
反之如果不是主线程调用,则我们需要把我们添加数据这个操作打成一个包,委托给控件的主线程去操作:
2、故我们首先定义一个包格式,即为委托,委托需要和WriteLog参数一致
private delegate void delWriteLog(Color color, string text, params object[] param);
delWriteLog log = new delWriteLog(WriteLog);
this.rtbx_system_log.Invoke(log, new object[] { color, text, param });
完成以上定义后则可以在任意地方直接调用WriteLog方法。
但是在某些并发调用的情况下面则会出现线程冲突的情况,我们这个时候就需要lock一下RichTextBox的操作
void WriteLog(Color color, string text, params object[] param)
{
if (!this.rtbx_system_log.InvokeRequired)
{
lock (logObject)
{
this.rtbx_system_log.ScrollToCaret();
this.rtbx_system_log.SelectionColor = color;
this.rtbx_system_log.AppendText(string.Format("{0}:{1}\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format(text, param)));
}
}
else
{
delWriteLog log = new delWriteLog(WriteLog);
this.rtbx_system_log.Invoke(log, new object[] { color, text, param });
}
}