2009-11-15 5 views
0

System.Net.Sockets.NetworkStream.BeginRead이 완료되면 비동기 적으로 호출되는 메서드가 있습니다.비동기 콜백 메소드의 UI 스레드와 상호 작용합니까?

skDelegate = New AsyncCallback(AddressOf skDataReceived) 
skStream.BeginRead(skBuffer, 0, 100000, skDelegate, New Object) 

해당 콜백 메서드에서 UI 스레드와 상호 작용해야합니다.

Sub skDataReceived(ByVal result As IAsyncResult) 
    CType(My.Application.OpenForms.Item("frmMain"), frmMain).refreshStats(d1, d2) 
End Sub 

이렇게하면 메서드가 완료된 후에 예외가 발생합니다. (최종 서브 실행)

실행 취소 동작 이 대응하는 세트 동작 적용된 것과는 상이한 콘텍스트 발생. 가능한 원인은 컨텍스트가 스레드에 설정되었고 이 되돌릴 수 없음 (실행 취소)입니다.

그렇다면 콜백 메소드의 UI 스레드와 어떻게 상호 작용합니까? 내가 도대체 ​​뭘 잘못하고있는 겁니까?

답변

2

frmMain 개체에서 Invoke 또는 BeginInvoke를 사용하여 UI 스레드에서 실행할 메시지 (대리자)를 큐에 넣어야합니다.

다음은 C#에서이 작업을 수행하는 방법입니다.

 
frmMain.Invoke(() => frmMain.refreshStats(d1, d2)); 

또한 확인하십시오 (list of Invoke types and their uses).

+0

하는 경우를 나는 frmMain을 직접 호출하는데, 윈도우 핸들이 생성 된 후에 만 ​​호출이 컨트롤에서 호출 될 수 있다는 오류가 발생합니다. 그래서 OpenForms 컬렉션에서 폼을 사용하려고했지만, 이전의 "The Undo operation ..."과 같은 오류가 발생했습니다. 무엇을 잘못하고 있습니까? –

+0

즉, "해결책"은 내 기본 문제 인 InvalidContextException을 해결하지 않습니다. 어쨌든 누군가가 이것을 다시 만나면 나는 이것에 대한 답을 찾았습니다. 아래 내 대답을 참조하십시오. –

+0

그래서 기본적으로 내가 생각하는 것은 Windows가 폼 창에 대한 Win32 핸들을 만들기 전에이 코드가 실행되고 있다는 것입니다. 나는이 코드가 실행되기 전에 윈도우가 보이는지 궁금하다. –

0

내가 (실제로 해결!) 솔루션을 발견 나는 UI 스레드에서 양식에서 속성을 읽어도 상호 작용 또는 때마다 내가 가진 것을 반복 InvalidContextException 오류로.

Async 콜백 메서드에서 UI 스레드와 상호 작용하기 전후에 실행 컨텍스트를 백업하고 복원해야했습니다. 그런 다음 예외가 나타남에 따라 신비하게 사라집니다. 속성을 읽고 쓰거나 메소드를 호출하고 비동기 콜백에서 UI 스레드로 원하는 것을 수행 할 수 있습니다. 단, 대리자 나 호출을 사용하지 않아도됩니다!

이 예외는 실제로 .NET Framewok 자체의 LOW 수준 버그입니다. Microsoft Connect bug report을 참조하십시오. 그러나 기능상의 문제 해결 방법은 나와 있지 않습니다.

해결 방법 : (생산 코드)

Sub skDataReceived(ByVal result As IAsyncResult) 

    // backup the context here 
    Dim syncContext As SynchronizationContext = AsyncOperationManager.SynchronizationContext 

    // interact with the UI thread 
    CType(My.Application.OpenForms.Item("frmMain"), frmMain).refreshStats(d1, d2) 

    // restore context. 
    AsyncOperationManager.SynchronizationContext = syncContext 
End Sub 
+1

매우 흥미 롭습니다. 잘 했어. –

1

당신은 UI 스레드가 frmMain.refreshStats 메소드를 호출이 필요합니다. Control.InvokeRequired 속성과 Control.Invoke (MSDN Documentation)를 사용하면 여러 가지 방법으로이 작업을 수행 할 수 있습니다.

"EndAsync"메서드를 사용하면 메서드 호출 UI 스레드를 안전하게 만들거나 refreshStats 메서드에서 스레드 안전성을 검사하도록 할 수 있습니다 (Control.InvokeRequired 사용).

EndAsync UI 스레드 안전이 같은 것입니다 :

Public Delegate Sub Method(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2) 

Sub skDataReceived(ByVal result As IAsyncResult) 
    Dim frmMain As Form = CType(My.Application.OpenForms.Item("frmMain"), frmMain) 
    Dim d As Method(Of Object, Object) 
'create a generic delegate pointing to the refreshStats method 
    d = New Method(Of Object, Object)(AddressOf frmMain.refreshStats) 
'invoke the delegate under the UI thread 
    frmMain.Invoke(d, New Object() {d1, d2}) 
End Sub 

또는 당신은 UI 스레드에서 자신을 호출 할 필요가있는 경우 볼 수있는 refreshStats 방법을 확인 할 수 있습니다 :

Public Delegate Sub Method(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2) 

Sub refreshStats(ByVal d1 As Object, ByVal d2 As Object) 
'check to see if current thread is the UI thread 
    If (Me.InvokeRequired = True) Then 
     Dim d As Method(Of Object, Object) 
'create a delegate pointing to itself 
     d = New Method(Of Object, Object)(AddressOf Me.refreshStats) 
'then invoke itself under the UI thread 
     Me.Invoke(d, New Object() {d1, d2}) 
    Else 
     'actual code that requires UI thread safety goes here 
    End If 
End Sub 
+0

이 짝을 모두 시도했지만 실제 예외가 해결되지 않았습니다! 해결 방법은 내 대답을 참조하십시오. –

관련 문제