2012-01-07 47 views
3

我有一个简单的应用程序与通常的UI线程和后台工作人员,我需要动态创建LinkLabels并将它们放在FlowLayoutPanel中的后台工作。为了做到这一点,我需要将LinkLabel的父级设置为FlowLayoutPanel。多线程,访问UI控件

这是我现在有的代码片段,但是,我得到了'l.Parent = panel'这一行中臭名昭着的“跨线程操作无效”

我对多线程操作相当陌生,但我认为我做了正确的调用,但显然不是。有什么建议么?

LinkLabel l = new LinkLabel(); 
if (rssFeedPanel.InvokeRequired) { 
    FlowLayoutPanel panel = null; 
    rssFeedPanel.Invoke(new MethodInvoker(delegate { panel = rssFeedPanel; })); 
    l.Parent = panel; 
} 
else 
    l.Parent = rssFeedPanel; 

回答

3

您需要实际设置其他线程上Parent财产。

LinkLabel l = new LinkLabel(); 
if (rssFeedPanel.InvokeRequired) { 
    rssFeedPanel.Invoke(new MethodInvoker(delegate { 
     l.Parent = rssFeedPanel; 
    })); 
} 
else 
    l.Parent = rssFeedPanel; 

通常,几乎所有涉及访问UI控件成员的操作都只能通过UI线程完成。一些明显的例外是Invoke,InvokeRequired,BeginInvoke以及BackgroundWorker类的一些方法。

如果您想要这种情况,您还可以使用BeginInvoke而不是Invoke

+0

感谢您的帮助! – Hammy 2012-01-07 23:05:54

+0

只是好奇,你不能使用'if(Dispatcher.Thread == Thread.CurrentThread)'并调用Dispatcher.BeginInvoke(new EventHandler ())来调用所有控件,而不是检查每个控件是否有InvokeRequired控制?只是一个大脑放屁,但如果可以的话,我很确定它有点快。 (需要你开启一个事件或者通过'EventArgs'传递这些东西,但这很简单) – aevitas 2012-01-08 00:54:08

+0

'Dispatcher.Thread'是非静态的,所以你需要UI线程的实例。至于速度更快,我怀疑它。从看代码我敢打赌,如果控制窗口已经创建,它就差不多了。如果窗口还没有创建,我敢打赌'Control.InvokeRequired'更快。 – 2012-01-08 01:19:28

3

我建议你把你的逻辑放在一个方法中,首先检查InvokeRequired是否在Invoke中调用该方法,否则直接调用它。

if (rssFeedPanel.InvokeRequired) { 
    rssFeedPanel.Invoke(new MethodInvoker(delegate 
    { 
     AddLabel(); 
    })); 
} 
else AddLabel(); 

并把你的逻辑在AddLabel方法:

private void AddLabel() 
{ 
    LinkLabel l = new LinkLabel(); 
    l.Parent = rssFeedPanel; 
}