我正在研究在window_load上调用函数populate()的应用程序
此功能执行大约需要1分钟才能完成。我想让这个函数在单独的线程中调用。
我正在使用以下代码
Thread thread = new Thread(PopulateAndDrawGraph);
thread.Start();
在此函数的最后一行是
nodeXlControl1.DrawGraph(真);
此处发生异常
调用线程无法访问此对象,因为另一个线程拥有它。
实际发生了什么错误
答案 0 :(得分:2)
您只能从创建控件的同一个线程中访问UI控件,这通常是UI线程本身。
您需要以能够识别线程的方式更改代码。
这是一篇发表在MSDN杂志上的精彩文章:Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads,它将详细解释你如何做你想做的事。
这篇文章有点陈旧,但同样的原则仍然适用。
我认为较新的C#语言功能 - 比如新的async
/ await
关键字 - 应该可以让您的任务更轻松。
但请记住,仍然存在访问UI控件的相同旧限制。没有办法理解文章中描述的基础知识。
答案 1 :(得分:1)
有两种方法可以解决这个问题,一种正确的方式和另一种方式:
1:如果你想要一个好的工作解决方案,那么这应该可以解决问题,..
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.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
msdn.microsoft.com/en-us/library/ms171728.aspx
2:但如果你想要一个快速的解决方案而不保证它能正常工作,只需设置这个变量: Control.CheckForIllegalCrossThreadCalls = False
答案 2 :(得分:0)
问题是,任何UI交互必须发生在应用程序的主线程中。我的建议是你在单独的线程中绘制计算,但是在一个对象中收集你的结果。线程完成后,您可以从该对象中提取结果,并将其放置在nodeXlControl1。
可悲的是,我不知道有关你的目标的细节,解决方案的总和就是这个。 如果你能告诉我这方面的更多细节,我可以进一步帮助你。
答案 3 :(得分:0)
在这里查看this article (How to: Make Thread-Safe Calls)。它解释了有关跨线程调用的所有相关项目。我还建议您在c#中查看“任务”的概念。这是一个写得很好的lib,可以帮助你处理并行性和类似的概念!
答案 4 :(得分:0)
由于您尝试从线程访问UI元素,因此需要调用Invoke
。所以在PopulateAndDrawGraph
你应该有:
Invoke((Action)(() =>
{
nodeXlControl1.DrawGraph(true);
}));
答案 5 :(得分:0)
除了创建此控件的线程之外,您无法从任何其他线程访问UI控件(您只能从主UI线程访问/更改UI控件属性)。通过此链接,我希望这能让您清楚Cross-thread operation not valid
答案 6 :(得分:0)
我在c#中使用了BackgroundWorker类。