2012-08-28 7 views
2

거기에는 비슷한 질문이 많이 있고 그 중 많은 부분을 읽었습니다. 불행히도, 나는 그들을 통해 읽은 후에도 여전히 내 문제를 해결할 수 없다 - 그러나 나는 C#에 비교적 익숙하지 않다. docs에 따르면 스레드 안전하지 않은 문제는 디버거를 사용할 때 InvalidOperationException이됩니다. 이것은 내 문제의 경우가 아닙니다.다른 양식으로 대화 상자 업데이트하기

간단한 생생한 테스트 클래스로 문제를 재 작성하여 내 문제에 집중했습니다.

기본 양식은 일종의 진행 대화 상자를 표시합니다. 그 코드는 기본 폼에서 모든 호출()없이 호출

public partial class ImportStatusDialog : Form 
{ 
    public ImportStatusDialog() 
    { 
     InitializeComponent(); 
    } 

    public void updateFileStatus(string path) 
    { 
     t_filename.Text = path;   
    } 

    public void updatePrintStatus() 
    {  
     t_printed.Text = "sent to printer"; 
    } 

    public void updateImportStatus(string clientName) 
    { 
     t_client.Text = clientName; 
    } 

    public void updateArchiveStatus() 
    { 
     t_archived.Text = "archived"; 
    } 
} 

:

private void button1_Click(object sender, EventArgs e) 
    { 
     ImportStatusDialog nDialog = new ImportStatusDialog(); 

     nDialog.Show(); 

     nDialog.updateFileStatus("test"); 
     Thread.Sleep(1000); 
     nDialog.updateImportStatus("TestClient"); 
     Thread.Sleep(1000); 
     nDialog.updatePrintStatus(); 
     Thread.Sleep(1000); 
     nDialog.updateArchiveStatus(); 
     Thread.Sleep(1000); 

     nDialog.Close(); 
    } 

그리고 심지어는 같이 호출했을 때,

private void button3_Click(object sender, EventArgs e) 
    { 
     ImportStatusDialog nDialog = new ImportStatusDialog(); 

     nDialog.Show(); 

     if (this.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate 
      { 
       nDialog.updateFileStatus("Test"); 
      }); 
     } 
     else 
     { 
      nDialog.updateFileStatus("Test"); 
     } 

     Thread.Sleep(1000); 

     if (this.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate 
      { 
       nDialog.updatePrintStatus(); 
      }); 
     } 
     else 
     { 
      nDialog.updatePrintStatus(); 
     } 

     Thread.Sleep(1000); 

     if (this.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate 
      { 
       nDialog.updateImportStatus("cName"); 
      }); 
     } 
     else 
     { 
      nDialog.updateImportStatus("cName"); 
     } 

     Thread.Sleep(1000); 

     if (this.InvokeRequired) 
     { 
      this.Invoke((MethodInvoker)delegate 
      { 
       nDialog.updateArchiveStatus(); 
      }); 
     } 
     else 
     { 
      nDialog.updateArchiveStatus(); 
     } 

     Thread.Sleep(1000); 

     nDialog.Close(); 
    } 

처럼 보이는 대화 이 디자이너 (내 예제에서)

designer view

그런 식으로 표시됩니다

dialog at runtime

내가 correnctly 대신 Show() 대화 상자가 표시됩니다의 ShowDialog()를 사용하는 경우,하지만 API의 문서가

지적과 같이 표시하려면이 방법을 사용할 수 있습니다 응용 프로그램의 모달 대화 상자 이 메소드가 호출 될 때 코드는 대화 상자가 나는 그것이 한 후 대화 업데이트는 일어날 것을 의미 특히, 원하는하지 않은

을 닫을 때까지 실행 아닌 다음 다시 닫혔다.

내가 뭘 잘못하고 있니? 이것은 사소한 문제인 것처럼 보이지만 그 해결책이 나를 피합니다. C# GUI 프로그래밍에 익숙하지 않다는 것을 명심하십시오.

또한 Invoke()를 사용하기에 적합한 장소는 무엇입니까? 대화 상자 메서드를 호출 할 때 또는 대화 상자 업데이트 메서드 자체를 호출 할 때 주 폼에서 사용합니까?

+1

버튼 클릭 핸들러에서 기본 UI 스레드를 차단하고 있습니다. 즉, 창을 다시 그릴 수 없습니다. – adrianbanks

+0

어떻게 방지 할 수 있습니까? 이 예제에서 이벤트는 버튼 클릭 핸들러에 의해 발생합니다. 내 현실 세계의 문제 시나리오에서 이벤트는'FileSystemWatcher'에서 왔습니다. 그러나 두 경우 모두 이벤트에 반응하고 싶습니다 – LumenAlbum

+1

근본적으로 잘못하고 있습니다. GUI 프로그래밍은 콘솔 모드 프로그래밍과 전혀 다릅니다. 필요한 부분을 추측 할 수 없으며 실제로 책을 읽을 필요가 있습니다. –

답변

2

여기에 여러 개의 스레드를 사용하는 것처럼 보이지 않으므로 호출 항목이 필요하지 않습니다. 호출은 크로스 스레드 호출에만 필요합니다. 여러 폼을 작성하지만 모든 코드는 동일한 스레드에서 실행됩니다.

(버튼 클릭 이벤트에 코드가 있음을 암시하는 것처럼) 기본 UI 스레드에서 작업하는 경우 주기적으로 Application.DoEvents()을 호출하여 진행 양식을 새로 고침 할 수 있습니다.

더 나은 해결책은 작업을 위해 BackgroundWorker을 사용하고 주기적으로 진행 상황을보고하는 것입니다.

그런 다음 BackgroundWorker의 ProgressChanged 이벤트 (기본 스레드에서 실행되므로 아무 것도 호출 할 필요가 없음)에서 진행률 양식을 업데이트 할 수 있습니다.

+3

Application.DoEvents()에 대한 권장 사항을 피하십시오. 더 나은 솔루션으로 BackgroundWorker에 대해 언급 한 경우에도 마찬가지입니다. – varg

+0

메인 프로그램 스레드와 C# GUI/이벤트 발송 스레드에서 이미 2 개의 스레드가 실행 중이라고 생각했습니다. – LumenAlbum

+1

아니요, GUI 스레드는 기본 스레드입니다. 그래서 버튼 핸들러에서 너무 많은 작업을 할 때 윈도우가 응답을 멈추게됩니다. – Blorgbeard

관련 문제