2010-12-31 3 views
4

여러 WinForm 컨트롤을 업데이트하는 두 개의 비 UI 스레드가있는 코드를 상속 받았습니다.
코드에서 InvokeRequired 및 Invoke를 사용하여 UI를 업데이트합니다. 그러나, 나는 여전히 오류가 발생합니다 : 교차 스레드 작업이 유효하지 않습니다 : 'lvReports'가 작성된 스레드가 아닌 다른 스레드에서 액세스되었습니다.Winform : 여러 스레드 동시에 UI 업데이트

경쟁 조건을 다루고 있으며 아래 메서드에 잠금 기능을 도입해야한다고 생각하지만, UI가 아닌 스레드에서 UI를 안전하게 업데이트하는 방법에 대한 예제는 수십 가지가 있지만 실제로는 없습니다. 경합 시나리오에서 동일한 컨트롤을 업데이트하는 두 개의 스레드를 처리하는 방법에 대한 예제 또는 토론.

그럼 내 질문은 : 경쟁 조건에서 UI를 올바르게 업데이트하고 UI가 아닌 스레드에서 UI를 업데이트해야하는 경우 아래 코드를 어떻게 다시 작성해야합니까?

// two separate theads call this method in a instance of a WinForm 
private void LoadReports() 
{ 
    if (this.InvokeRequired) 
    { 
    this.Invoke(new MethodInvoker(this.LoadReports)); 
    } 
    else 
    { 
    // some code removed to keep exampe simple... 
    SetCtlVisible(lvReports, true); 

    if (this.InvokeRequired) 
    { 
     this.Invoke((MethodInvoker)delegate { lvReports.Refresh(); }); 
    } 
    else 
    { 
     lvReports.Refresh(); 
    } 
    } 
} 

delegate void SetVisibleCallback(Control ctl, bool visible); 
private void SetCtlVisible(Control ctl, bool visible) 
{ 
    if (ctl.InvokeRequired) 
    { 
    SetVisibleCallback d = new SetVisibleCallback(SetCtlVisible); 
    ctl.Invoke(d, new object[] { ctl, visible }); 
    } 
    else 
    { 
    ctl.Visible = visible; 
    } 
} 

여기에 몇 가지 생각은 다음과 같습니다 언제든지 ctl.InvokeRequired 다를 this.InvokeRequired합니까? 첫 번째로 두 번째 InvokeRequired 테스트가 필요합니까? 첫 번째 InvokeRequired를 유지하면 SetCtlVisible 구현이 필요합니까? 첫 번째 InvokeRequired를 삭제하고 else 절의 모든 코드를 유지해야합니까? else 절에서 잠금이 필요합니까?

답변

9

이와 같이 InvokeRequired를 사용하면 반 패턴이 발생합니다. 이 메서드가 스레드에서 호출되는을 알고 있으면 InvokeRequired가 항상 true 여야합니다.

이제 문제를 해결하는 데 사용할 수 있습니다. 거짓이면 심각한 문제가 있습니다. 예외를 throw하면 디버거가 멈추고 왜 제대로 작동하지 않는지 알 수 있습니다. 그리고 항상 Invoke()를 호출하여 LoadReports()의 나머지 부분을 수행하는 작은 도우미 메서드를 호출합니다.

코드의 나머지 부분에서도 잘못 사용하고 있습니다. LoadReports()의 나머지 부분이 UI 스레드에서 실행된다는 것을 알고 있으므로 Invoke()를 사용했습니다. SetCtlVisible()을 포함하여 다시 테스트 할 필요가 없습니다.

폭탄을 가져 오는 일반적인 이유는 스레드가 LoadReports()를 너무 빨리 실행하여 양식의 창을 만들기 때문입니다. 그것을 연동시켜야합니다. 폼의 Load 이벤트는 신호입니다.

+0

감사합니다.이 키는 스레드가 LoadReports()를 실행할 때 완전히로드되지 않는 형식이었습니다. InvokeRequired에 대한 불필요한 호출도 모두 제거했습니다. – Zamboni

관련 문제