2012-01-07 73 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; 
}