2011-09-06 2 views
4

UI 컨텍스트에서 작업의 ContinueWith 메서드를 사용하면 크로스 스레드 예외를 발생시키지 않고 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 스레드에서 만든 컨트롤에이 컨트롤을 추가하려고하면 예외가 발생합니다.

이 작업을하려면 컨트롤 만들기와 작업을 분리해야합니다. Control이 아닌 Func<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); 

(이 윈폼을 가정하고) 당신이 MOR 제어 리팩토링을 원한다면 방법으로 추가 Enigmativity 당신이에 allways 같은 것을 할 수 allready 말한 이유와 가능한 해결책을 제외하고

+0

답장을 보내 주셔서 감사합니다. 당신은 꽤 정확했습니다. SomeWorkMethod는 자체 컨트롤을 만드는 사용자 정의 컨트롤을 만들고있었습니다. 이 UI는 동일한 UI 스레드 (작업을 사용하지 않는 경우 예외가 발생하지 않음)에서 수행되어야하지만, ContinueWith 작업에서이 사용자 정의 컨트롤을 사용할 때 예외가 발생했습니다. 내 궁극적 인 해결책은 StartNew 메서드에서 UI 컨텍스트를 그대로 사용하는 ContinueWith 메서드와 마찬가지로 사용하는 것이 었습니다. – Amberite

+0

실제로 이것에 대해 좀 더 생각한 후에 StartNew 메서드에서 생성 된 사용자 정의 컨트롤은 별도의 스레드에 포함된다는 것을 완벽하게 이해할 수 있습니다. 어떻게 든 완전히 빠져서 바보입니다. 어쨌든, 모두 해결되었습니다 :) – Amberite

7

필요한 경우와 호출 내에서 자신을 호출하는 방법 내부의 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