我正在增强一个c#win表单应用程序,它通过webservices与SalesForce CRM交互。
我有以下代码对我的表单上的标签进行“线程安全”更新:
delegate void SetTextCallback(string text);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lblAccessStatus.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.lblAccessStatus.Text = text;
this.lblAccessStatus.Refresh();
}
}
我的表单(称为SFDetachifier.cs
)有一个按钮执行,它接受两个日历控件的日期然后调用:
lblAccessStatus.Visible = true;
picProgress.Visible = true;
string fromDate = dtManualFromDate.Value.ToString("yyyy-MM-dd") + fromTime;
string toDate = dtManualToDate.Value.ToString("yyyy-MM-dd") + toTime;
string[] arg = new string[] { "S1", fromDate, toDate };
SFCtrl._SessionLog.Append("Manual detach requested on " + SFOrgName + "\n");
SFCtrl._SessionLog.Append("Date range requested: " + fromDate + " to " + toDate + "\n");
bgProcessing_Production.RunWorkerAsync(arg);
bgProcessing_Production
具有以下代码,用于后台工作人员,其中包含对setText
的调用
private void bgProcessing_Production_DoWork(object sender, DoWorkEventArgs e)
{
String[] args = (String[])e.Argument;
e.Result = args[0];
// clear the datagrid view
gvTaskCases.DataSource = null;
//gvTaskCases.Rows.Clear();
//if (gvTaskCases.Rows.Count != 0)
// {
// gvTaskCases.Rows.Clear(); // .Update();
// }
SetText("login to SalesForce (on " + SFOrgName + ") ...please wait");
现在,当我运行我的应用程序时,我设置了一些日期,然后通过单击执行按钮执行上面的代码,它完成它的工作(调用SalesForce XML Web服务)并将结果放在网格中。
一切正常,当我尝试再次运行程序时(例如,使用不同的日期)问题就出现了
然后我收到错误'跨线程操作无效:控件''从创建它的线程以外的线程访问。'
我不明白,我有委托设置吗?
我做错了什么 - 我猜测当背景工作者再次运行它会在新线程上运行,因此线程不安全。
我该如何解决此错误?
答案 0 :(得分:1)
你可以使用像这样的匿名代表来缩短一些事情:
private void removeGridDS()
{
this.gvTaskCases.Invoke((MethodInvoker)delegate
{
if (this.gvTaskCases.DataSource != null)
{
this.gvTaskCases.DataSource = null;
}
});
}
private void clear_gvTaskCases()
{
this.gvTaskCases.Invoke((MethodInvoker)delegate
{
if (this.gvTaskCases.Rows.Count != 0)
{
this.gvTaskCases.Rows.Clear();
}
});
}
现在您不需要硬编码的代理人。另外,你没有使用传入的bools。
答案 1 :(得分:0)
这是我为了解决这个问题而最终做的事情,正如上面提到的评论之一,它看起来很可能是对控件gvTaskCases
的调用导致错误,所以我创建了线程安全方法也调用该控件:
delegate void SetTextCallback(string text);
delegate void clear_gvTaskCasesCallback(bool clearIt);
delegate void remove_gvTaskCasesDSCallback( bool removeDS);
private void removeGridDS(bool removeDS)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.gvTaskCases.InvokeRequired)
{
remove_gvTaskCasesDSCallback d = new remove_gvTaskCasesDSCallback(removeGridDS);
this.Invoke(d, new object[] { removeDS });
}
else
{
if (this.gvTaskCases.DataSource !=null)
{
this.gvTaskCases.DataSource=null;
}
}
}
private void clear_gvTaskCases(bool clearIt)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.gvTaskCases.InvokeRequired)
{
clear_gvTaskCasesCallback d = new clear_gvTaskCasesCallback(clear_gvTaskCases);
this.Invoke(d, new object[] { clearIt });
}
else
{
if (this.gvTaskCases.Rows.Count != 0)
{
this.gvTaskCases.Rows.Clear();
}
}
}