2010-01-18 11 views
1

BackgroundWorker을 사용하여 GUI에서 데이터베이스 트랜잭션을 수행하고 싶습니다.BackgroundWorker의 완성을 어떻게 기다릴 수 있습니까?

BackgroundWorker에 작업을 수행하도록 명령 한 다음 GUI가 응답하는 동안 작업자가 완료 할 때까지 기다릴 수 있습니까?

이 목적으로 DoEvents을 사용해야합니까, 아니면 다른 방법이 있습니까?

답변

10

"어떻게 BackgroundWorker에 작업을 수행 한 다음 작업자가 GUI를 응답 상태로 유지할 때까지 기다릴 것입니까?" 실제로 "어떻게 BackgroundWorker을 사용합니까?"라는 질문을하고 있습니다. 그게 뭐야 BackgroundWorker입니다.

당신이 백그라운드 작업을 쓰기

, 당신은 기본적으로 네 조각으로 방법을 깨고있어 :

  1. 가 작업을 실행할 준비.
  2. 작업 자체.
  3. 작업이 실행되는 동안 UI로 진행보고.
  4. 작업 완료시 정리.

이렇게 네 가지 방법을 작성해야합니다. 첫 번째 방법은 BackgroundWorker을 만들고 이벤트 핸들러를 DoWork, ProgressChangedRunWorkerCompleted 이벤트에 추가하고 작업이 실행되는 동안 UI가 필요한 모든 상태로두고 RunWorkerAsync을 호출하여 작업을 시작하는 방법입니다.

나머지 세 개는 세 개의 이벤트 처리기입니다. DoWork은 작업을 수행하는 DoWorkEventHandler이며 진행 상황을 UI에보고해야 할 때마다 ReportProgress을 호출합니다. ProgressChangedReportProgress이 호출 될 때 실제로 UI를 업데이트하는 ProgressChangedEventHandler입니다. RunWorkerCompleted은 작업이 완료되었음을 UI에 알리는 RunWorkerCompletedEventHandler입니다.

그게 전부입니다.

글쎄, 전혀 아님 모두. 먼저 완성 처리기에서 Error 속성을 확인하고 처리해야합니다. 이렇게하지 않으면 do-work 메서드가 예외를 던진 것을 알 수있는 방법이 없습니다. UI 스레드에서 발생하지 않고 볼 수있는 예외를 throw하지 않기 때문입니다. (출력 창에 표시됩니다.)

둘째, DoWorkEventHandler이 UI의 아무 것도 만지지 않도록해야합니다. MVVM 패턴을 사용하고 있고 우발적 인 계획을 세우지 않았다면 까다로울 수 있습니다. 데이터 바인딩의 마법을 통해 UI에 바인딩 된 뷰를 업데이트하는 모델에 물건이있을 가능성이 높습니다. do-work 메서드 에서 모델을 조작하는 것은 UI를 조작하는입니다. INotifyPropertyChanged을 구현한다고 가정하면 여기서 문제를 피할 수있는 좋은 방법은 백그라운드 작업이 실행되는 동안보기가 PropertyChanged 이벤트를 발생시키지 않는 메커니즘을 만드는 것입니다.

또한 작업이 실행되는 동안 비활성화해야하는 UI 부분을 파악해야합니다. 이것은 UI에 따라 다릅니다. 대답은 "모든 것"일 수도 있고 그렇지 않을 수도 있습니다. 매력적인 진행 표시기에 대한 모달 형식을 사용하는 것 중 하나는 모달 폼이 열려있는 동안 전체 UI가 비활성화되어 있으므로이를 이해하지 않아도된다는 점입니다. 시작 메소드에서 컨트롤을 사용 중지하거나 속성 변경 알림을 사용 중지하는 경우 완료 메소드에서 다시 설정해야합니다.

그리고 UI의 활성 부분이 데이터 모델과 관련된 모든 업데이트는 잠재적 인 크로스 스레드 데이터 액세스 오류의 원인입니다. UI와 백그라운드 스레드가 동일한 객체를 업데이트하면 잘못된 처리가 발생합니다. 완료 핸들러에서 Error 속성을 처리하지 않으면 특히 좋지 않으며 크로스 스레드 예외는 알지 못하는 채 백그라운드 태스크를 종료합니다 . 내가이 집에 사는 것처럼 들린다면, 그것은 내가이 특별한 것을 잘못하는 것에 내 인생의 많은 시간을 잃어 버렸기 때문이다.

2

보통 진행 상황 표시 줄이있는 별도의 모달 형식으로 RunWorkerCompleted를 기다립니다. 이로 인해 최종 사용자는 작업을 마칠 때까지 기다려야하지만 GUI는 양식 등을 이동할 수있는 방식으로 응답합니다.

최종 사용자를위한 더 나은 솔루션은 예를 들어 상태 표시 줄에서 몇 가지 진행 상황을 렌더링하고 그/그녀는 당신의 프로그램 논리를 깨뜨릴 수없는 특정 작업만을 수행합니다.

이게 원하는가요?

+0

답장을 보내 주셔서 감사합니다. 백그라운드 프로세스를 시작하고 진행 상황 "회전 원"을 시작하여 작업자가 완료 될 때까지 기다린 다음 새로운 양식을 열지 않고 회전 원을 중지하려는 경우 - 회전 원은 기본 양식의 상태 표시 줄에 있습니다. – joek1975

+1

회전 표시 줄과 함께 진행률 표시 줄을 사용하거나 회전 원을 애니메이션화하기 위해 일부 독립적 인 Windows.Forms.Timer를 설정하거나 ProgressChanged 이벤트의 백분율 보고서를 사용할 수 있습니다. 자세한 내용은 http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspx를 참조하십시오. –

1

당신은 사용

Application.DoEvents(); 

하지만

기본적으로 BackgroundWorker 구성 스레드에서 UI를 업데이트하는 더 나은 방법을 this link을 읽어야합니다, 코드는 다음과 같다 :

// The declaration of the textbox. 
private TextBox m_TextBox; 

// Updates the textbox text. 
private void UpdateText(string text) 
{ 
    // Set the textbox text. 
    m_TextBox.Text = text; 
} 


public delegate void UpdateTextCallback(string text); 

그런 다음 스레드에서 m_TextBox의 Invoke 메서드를 호출하고 대리자를 호출하여 매개 변수를 전달할 수 있습니다.

this.backgroundWorker1.RunWorkerAsync(); 

을 그리고 당신은 RunWorkerCompleted 이벤트를 사용해야 할 것 :

m_TextBox.Invoke(new UpdateTextCallback(this.UpdateText), 
       new object[]{”Text generated on non-UI thread.”}); 

읽기 this link 또한, 자세한 내용은

1

에 대한 당신과 같이 RunWorkerAsync를 호출 할 수 있습니다.

는 여기에 MSDN에서 예제 :

private void backgroundWorker1_RunWorkerCompleted(
    object sender, RunWorkerCompletedEventArgs e) 
{ 
    // First, handle the case where an exception was thrown. 
    if (e.Error != null) 
    { 
     MessageBox.Show(e.Error.Message); 
    } 
    else if (e.Cancelled) 
    { 
     // Next, handle the case where the user canceled 
     // the operation. 
     // Note that due to a race condition in 
     // the DoWork event handler, the Cancelled 
     // flag may not have been set, even though 
     // CancelAsync was called. 
     resultLabel.Text = "Canceled"; 
    } 
    else 
    { 
     // Finally, handle the case where the operation 
     // succeeded. 
     resultLabel.Text = e.Result.ToString(); 
    } 

    // Enable the UpDown control. 
    this.numericUpDown1.Enabled = true; 

    // Enable the Start button. 
    startAsyncButton.Enabled = true; 

    // Disable the Cancel button. 
    cancelAsyncButton.Enabled = false; 
} 

그리고 바로 그거야. DoEvents에 전화 할 필요가 없다고 생각합니다. BackgroundWorker가 실행되는 동안 UI가 여전히 응답해야합니다.

관련 문제