2

我正在开发在 window_load 上调用函数 populate() 的应用程序

此函数执行大约需要 1 分钟才能完成。我想让这个函数在单独的线程中调用。

我正在使用以下代码

Thread thread = new Thread(PopulateAndDrawGraph);
        thread.Start();

在这个函数的最后一行是

nodeXlControl1.DrawGraph(true);

这里发生异常

调用线程无法访问此对象,因为不同的线程拥有它。

实际发生了什么错误

4

7 回答 7

2

您只能从创建控件的同一线程(通常是 UI 线程本身)中访问 UI 控件。

您将需要以使其成为线程感知的方式更改您的代码。

这是一篇发表在 MSDN 杂志上的精彩文章:Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads,它将详细解释如何做你想做的事。

这篇文章有点老了,但同样的原则仍然适用。

我猜想新的 C# 语言特性——比如 new async/await关键字——应该会让你的任务更容易一些。

但请记住,访问 UI 控件的旧限制仍然存在。无法理解文章中描述的基础知识。

于 2012-12-28T12:06:34.310 回答
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

于 2012-12-28T12:57:35.523 回答
0

问题是,任何 UI 交互都必须发生在应用程序的主线程中。我的建议是你在单独的线程中绘制计算,但将你的结果收集在一个对象中。线程完成后,您可以从该对象中提取结果,并将其放置在 nodeXlControl1 中。

可悲的是,我不知道有关您的目标的详细信息,解决方案的总和就是这样。如果你能告诉更多关于这个的细节,我可能会进一步帮助你。

于 2012-12-28T12:05:34.550 回答
0

在这里查看这篇文章(如何:进行线程安全调用)。它解释了有关跨线程调用的所有相关项目。我还建议您研究 c# 中“任务”的概念。有一个写得很好的库,可以帮助您处理并行性和类似的概念!

于 2012-12-28T12:07:36.917 回答
0

由于您尝试从线程访问 UI 元素,因此您需要调用Invoke. 所以PopulateAndDrawGraph你应该有:

Invoke((Action)(() =>
{
    nodeXlControl1.DrawGraph(true);
}));
于 2012-12-28T12:09:09.113 回答
0

除了创建此控件的线程之外,您无法从任何其他线程访问 UI 控件(您只能从主 UI 线程访问/更改 UI 控件属性)。通过这个链接,我希望这能让你清楚跨线程操作无效

于 2012-12-28T14:59:07.120 回答
0

我在 c# 中使用了 BackgroundWorker 类。

于 2013-01-04T06:40:37.960 回答