2011-09-06 39 views
4

我的印象是使用Task的ContinueWith方法與UI上下文允許在UI元素上執行操作而不會導致跨線程異常。但是,在運行以下代碼時,我仍然遇到異常:任務ContinueWith儘管UI上下文導致跨線程異常

var context = TaskScheduler.FromCurrentSynchronizationContext(); 

Task<SomeResultClass>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => 
    { 
     myListControl.Add(t.Result); // <-- this causes an exception 
    }, context); 

任何想法?

+0

任何你不使用'Invoke'來訪問UI控件的原因? – Yahia

+0

你是從調度員的線程開始執行任務嗎?如果不是這樣可以解釋它。 – BrokenGlass

回答

7

交叉線程異常有兩種不同的原因。

最常見的一種情況是您嘗試從非UI線程修改控件的狀態。這是而不是您遇到的問題。

你打的那個是控件必須在UI線程上創建。你的任務是在不同的線程上創建控件,當你試圖將這個控件添加到在UI線程上創建的控件時,你會得到異常。

您需要從控件創建中分離出工作來完成此工作。嘗試返回Func<Control>而不是Control,並在添加之前在UI線程上調用它。保持大部分工作在任務線程上,但是通過返回剛創建控件的Func<>來形成一個很好的緊密關閉。

var context = TaskScheduler.FromCurrentSynchronizationContext(); 

Task<SomeResultClass>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => 
    { 
     if (!myListControl.InvokeRequired) 
     myListControl.Add(t.Result); // <-- this causes an exception 
     else 
     myListControl.Invoke((Action)(() => myListControl.Add(t.Result))); 
    }, context); 

(假設這是的WinForms)

如果你想鐵道部控制重構的加入到一個方法:

+0

感謝您的回覆。你非常正確 - 我的SomeWorkMethod創建了一個用戶控件,它創建了自己的控件。儘管這應該在同一個UI線程上完成(如果不使用任務,這不會導致異常),但在ContinueWith操作中使用此用戶控件時,它會導致異常。我的最終解決方案是在StartNew方法中使用UI上下文,以及ContinueWith方法,然後運行。 – Amberite

+0

實際上,在思考了這一點之後,在StartNew方法中創建的用戶控件將處於單獨的線程中 - 我完全錯過了這個,這是愚蠢的。無論如何,所有已解決:) – Amberite

7
從原因和可能的解決方案Enigmativity告訴媒體鏈接,你可以八方通做這樣的事情

除了並使用InvokeRequired方法中調用自身的調用裏面,如果需要:

private void AddToListControl(MyItem item) 
{ 
    if (myListControl.InvokeRequired) 
    { 
     myListControl.Invoke((Action)(() => AddToListControl(item))); 
     return; 
    } 

    myListControl.Add(item); 
} 

什麼Enigmativity在暗示是someth荷蘭國際集團這樣的:

var result = 
    Task<Action>.Factory.StartNew(SomeWorkMethod).ContinueWith((t) => 
     { 
     return() => myListControl.Add(t.Result); 
     }); 

result.Result(); 

但恕我直言,這只是你從一開始就得到了,因爲你必須再次調用結果,操作正確的線程在同一個地方。

+0

只是我看到'.InvokeRequired'作爲「代碼味道」?即您需要一次作爲快速修復,現在可以隨處使用。 – adrianm

+0

我真的不知道 - 這只是一個小小的害蟲,如果你對UI編寫代碼,你一定要意識到 - 我傾向於在ViewModels中重構它,所以現在對我來說幾乎是很自然的。 – Carsten

+0

感謝您的精心製作!Enigmativity非常正確,因爲有一些控件是創建的,應該在同一個UI線程中創建,但出於某種原因,在使用任務時不會。我提高了你的壽命,因爲這在其他情況下是有用的信息。 – Amberite