我对C#很陌生,所以如果这是一个有点愚蠢的问题请原谅我。 无论如何,我正在写一个小聊天应用程序,到目前为止似乎进展顺利,我遇到了一个我似乎已修复的问题,但我希望找出为什么我需要这样做。
当我收到消息时,我想更新一个文本框,所以我使用:
txtConnectedID.Text = "test";
但是我收到了这个错误:
System.InvalidOperationException was unhandled by user code
Message=Cross-thread operation not valid: Control 'txtConnectedID' accessed from a thread other than the thread it was created on.
现在,我认为这与停止运行两次并且无法正确更新的方法有关?我不是百分之百。所以现在我有一个接受字符串的方法的委托,我调用:
private delegate void stringDelegate(string s);
BeginInvoke(new stringDelegate(writeToIPBox), new object[] { e.ConnectedIP.ToString() });
private void writeToIPBox(string newIP)
{
txtConnectedID.Text = newIP;
}
我不知道为什么我这样做,它有什么不同。我不是很高兴在不知道原因的情况下这样做。
提前致谢
答案 0 :(得分:1)
您应该只尝试从创建它们的线程更新控件。这有很好的理由,因为很容易遇到竞争条件。这些控件不是线程安全的,这是运行时帮助你。
相反,正如您已经想到的那样,您需要在UI线程上更新它,这是BeginInvoke
正在做的事情;在UI线程上异步调用委托。
答案 1 :(得分:0)
所有控件都由UI线程(其中只有一个)拥有,并且尝试从另一个线程访问它们会导致此异常。
BeginInvoke
在UI线程上调用指定的委托,这就是它工作的原因。您还可以通过选中txtConnectedID.InvokeRequired
来检查您是否在UI线程上。
答案 2 :(得分:0)
我花了一分钟坚定的谷歌搜索,但我最终找到了一个“授权”参考:
简短的回答(从该页面引用)是: Windows窗体中的控件绑定到特定的线程,并且不是线程安全的。
本文还提到如何“内部”处理这个问题...如果control.InvokeRequired
(即我们已经从另一个线程调用)在内部处理调用...而不是在整个代码中传播委托
就我个人而言,我从未真正质疑为什么要求代表,我就是这么做的。好问题。
干杯。基思。
答案 3 :(得分:0)
private static void SetText(TextBox tb, string text)
{
if (tb.InvokeRequired)
{
var stDelegate = new StDelegate(SetText);
tb.Invoke(stDelegate, new object[] { tb, text });
}
else
{
tb.Text = text;
}
}