2009-12-16 3 views
1

WPF에서 스레딩에 문제가 있습니다. 복잡한 사용자 인터페이스를 만들고 싶습니다. 그리고 나서 그것을 메인 윈도우에 추가하고 싶습니다. 이 복잡한 사용자 인터페이스를 생성하는 동안 내 메인 창에 진행률 표시 줄을 표시하고 싶습니다. 나는 이것이 쓰레드로만 만들어 질 수 있다고 생각한다. 그러나 문제가 있습니다. 작성된 요소는 별도의 스레드에서 작성되므로 기본 창에 추가 할 수 없습니다. 백그라운드 스레드에서 생성 된 UIElements를 주 스레드로 전송할 가능성이 있는지 아는 사람이 누구인지 확인하십시오. 간단한 방법으로 시도하면 객체가 별도의 스레드에 있기 때문에 액세스 할 수 없다는 메시지가 표시됩니다. 이미 진행 바 스레드를 안전하게 만들었습니다.백그라운드 스레드에서 요소를 만든 다음 주 인터페이스에 추가하십시오.

다음 예는 내가 원하는 것보다 조금 더 설명하기를 바랍니다.

StackPanel tcForm = new StackPanel(); 
Semaphore loadedSema = new Semaphore(0,1); 
Thread thread = new Thread(new ThreadStart(delegate(){ 
      //Formular should be created in background    
      tcForm.Children.Add(new Formular()); 
      ProgressBar.AddProgress(); 
      //...other things 
      loadedSema.Release(); 
})); 
thread.start(); 
loadedSema.WaitOne(); 

new Formular()는 매우 오랜 시간 실행, 그래서 백그라운드에서 만드는 방법에 대해 생각했다.

Formular을 변수에 추가 한 다음 주 스레드를 추가하는 것도 불가능합니다.

//this is also impossible 

//in background-thread 
form = new Formular 

//in main-thread 
tcForm.Children.Add(form); 

나는이 방법이 있기를 바랍니다. 어떤 조언,

감사가있는 경우 당신이 원하는 모든 업데이트가 진행 표시 줄 (또는 유사) 인 경우 다음 메인 스레드에서 앞까지 모든 UI를 만들어야 마틴

답변

3

... 
     this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(new Formular()); 
      ProgressBar.AddProgress();};) 
.... 

편집
가 긴 작동하는지 당신은 파견 전에) 객체를 Fromular를 (만들 수 있습니다

var f = new Formular(); 
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f); 
       ProgressBar.AddProgress();};) 
1

, 좋은 것이며, 양식의 Invoke method을 사용하여 배경 스레드의 상태 업데이트를 주 스레드로 보내십시오 (예 : int을 보내 0-100 % 사이의 진행률을 말하십시오)

Windows 양식 컨트롤을 공유하는 방법이 없다고 생각합니다. 스레드.

편집 : 좋아, 이제이 태그가 WPF라는 것을 알 수 있습니다. 응답은 동일하게 유지되지만 컨트롤을 호출하는 대신 Dispatcher 클래스를 사용합니다 (각 그래픽 요소는 적절한 디스패처에 대한 참조를 보유합니다). 다른 답변에서 제안 된대로 BackgroundWorker 클래스를 사용할 수도 있습니다.

+0

입니다. 그러나이 방법을 사용하면 문제는 진행 표시 줄이 다른 창에 있어야한다는 것입니다. 그리고이 창은 주 창 자식이 될 수 없습니다. – martin

1

저는 WPF에 대해 많이 알지 못합니다.하지만 저는 BackGroundWorker에 대해 알았습니다.

http://dotnetperls.com/backgroundworker

당신은 작업 후 발생 및 메인 쓰레드에서 실행해야 WorkerCompleted 이벤트를 처리해야합니다. 또한 진행률을보고하여 진행률 막대를 업데이트 할 수 있습니다.

예 : 당신은 Dispatcher.Invoke이 방법을 사용해야합니다

void worker_Start() 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += 
      new DoWorkEventHandler(worker_DoWork); 
     worker.RunWorkerCompleted += 
      new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 

     worker.RunWorkerAsync("MyArg"); 

    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     e.Result = new Formular(); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     this.Controls.Add((Control)e.Result); 
    } 
+0

배경 작업자를 사용하는 경우 스레딩을 사용하는 것과 같은 문제가 발생합니다. backgroundworker는 스레드이기 때문에 이것은 이해할 수 있습니다. Backgroundworker 스레드의 차이점은 Backgroundworker가 스레드 풀 – martin

+0

의 기존 스레드라는 것입니다. 주 스레드에서 BackgroundWorker를 만들고 WorkerCompleted 이벤트에 연결하면이 이벤트 처리기 내의 코드가 주 스레드에서 실행되어야합니다 (적어도 나를 위해 일한다). 나는 예제를 추가했다. –

0

아니요 - 불가능합니다. WPF는 주로 단일 스레드입니다.

그러나 인터페이스 작성에 많은 시간이 걸리는 이유는 무엇입니까? WPF는 매우 빠릅니다. "보통"제어 생성이 병목 현상이되어서는 안됩니다.

아마도 다른 개체 생성을 최적화 할 수 있습니다. 응용 프로그램의 프로파일 링을 시도하십시오.

UI를 아래에서 위로 빌드하십시오. 마지막 동작은 양식에 컨트롤을 추가해야합니다.

0

UAM 요소를 XAML로 직렬화 한 다음 주 스레드로 다시 보낼 수 있습니다. 하지만 주 스레드에서 첫 번째 위치에 생성하는 것보다 직렬화를 해제하는 것이 더 빠르지는 확실하지 않습니다. 현재 작동하는 방법은

관련 문제