在下面的代码MessageReceived
与label1
位于不同的主题上,当尝试访问它时,我会收到此错误:
跨线程操作无效: 从a访问控制'label1' 线程以外的线程 创建于。
foo.MessageReceived += new Agent.MessageReceivedHandler(foo_MessageReceived);
void foo_MessageReceived(Message message)
{
label1.Text = message.Body;
}
我该如何解决这个问题?
更多:显然我需要使用delegate
和invoke
,但我不知道如何,您能否详细解释一下?
答案 0 :(得分:4)
希望这将完全复制,但如果不是:
请勿从非GUI线程触摸GUI。使用BackgroundWorker并适当地报告进度,或者阅读the WinForms page of my threading article以获得更直接的控制(Control.Invoke / BeginInvoke)。
答案 1 :(得分:1)
委托将标签更新到创建标签的线程,而不是直接尝试更新标签。
答案 2 :(得分:1)
您需要使用Control.Invoke(或Control.BeginInvoke)。首先,创建一个新的Windows窗体应用程序并添加标签和按钮。双击Visual Studio中的按钮编辑它的Click事件并添加以下代码:
private void button1_Click(object sender, EventArgs e)
{
new System.Threading.Thread(new System.Threading.ThreadStart(Run)).Start();
}
void Run()
{
label1.Invoke(new Action(delegate()
{
label1.Text = System.Threading.Thread.CurrentThread.Name + " " + System.DateTime.Now.ToString();
}));
}
答案 3 :(得分:0)
这完全没有帮助。我希望自己可以投票。
我可能已经过时了,但从我记得的情况来看,除了主线之外,你不允许在GUI中改变任何东西。
答案 4 :(得分:0)
在您的Agent类中,当您引发MessageReceived事件时,您必须检查事件处理程序的Target是否实现了ISynchronizeInvoke。 如果是,并且InvokeRequired属性返回true,则必须调用eventhandler。
如果您不使用WinForms,而是使用WPF,则不能再依赖ISynchronizeInvoke,因为WPF控件不实现该接口。 相反,您必须使用AsyncOperation和AsyncOperatoinManager。
答案 5 :(得分:0)
始终确保在主线程(GUI线程)上更新GUI。
foo.MessageReceived + = new Agent.MessageReceivedHandler(foo_MessageReceived);
public delegate void MyDelegate(Message msg);
void foo_MessageReceived(Message message)
{
if (InvokeRequired)
{
BeginInvoke(new MyDelegate(foo_MessageReceived),new object[]{message});
}
else
{
label1.Text = message.Body;
}
}