2013-02-13 3 views
2

몇 가지 심각한 스왑/대체 작업을 위해 큰 Txt 문서를 WPF 앱으로 읽고 있습니다. 파일은 실제로는 3D STP 모델이므로 상당히 크지 만이 프로젝트의 원시 텍스트로 작업하고 있습니다. 파일을 여러 번 열지 않고 비교하기 쉽도록 List에 파일을 읽습니다..TXT를 ListBox에 실시간으로 읽으십시오.

어쨌든, 줄을 추가 할 때마다 동적으로 스크롤 할 목록 상자를 얻으려고합니다. 사용자가 콘솔 윈도우를 추가하면 파일 크기에 따라 약간의 시간이 걸릴 수 있으므로 사용자가 볼 수 있습니다. 총 행 수를 읽으면서 진행 표시 줄을 추가했습니다.

작업 진행에 따라 진행률 표시 줄이나 ListBox가 업데이트되지 않습니다. 최종 출력은 완료된 목록 상자의 토지가되며, 진행률 막대는 동시에 최대 0부터 시작합니다.

은 매우 간단하다, 내가 뭐하는 거지의 요지입니다 :

foreach (string Line in OriginalSTPFile.Lines) 
    { 
     string NewLine = EvaluateString(Line); //string the modified to whatever here 
     pBar.Value++; //increment progressbar 

     OutputWindow.Items.Add(NewLine); //add line to the ListBox 
    } 

난 그냥 목록 상자 진행 변화에 따라 실시간으로 업데이트 할 수 진행률 표시 줄을합니다. 나는 다음을 사용했다 :

Dispatcher.BeginInvoke(new Action(() => OutputWindow.Items.Add(NewLine)); 

같은 결과가 나왔다. 좀 더 정교한 멀티 스레딩 방법이 필요합니까? 크로스 스레드 예외를 생성하지 않았으므로 첫 번째 메서드가 작동했을 것이라고 가정했습니다.

+0

는 "실시간"으로 무엇을 의미합니까 전체 계획의 사이비 - 코드는? 상당히 큰 것은 무엇입니까? 또한 진행률 막대를 업데이트하는 단계 기능을 게시하십시오. –

+0

에서와 같이, 라인이 "평가"될 때마다 결과는 즉시 ListBox에 인쇄되고 프로 그스 바는 그에 따라 움직입니다. 다음 행이 평가되기 전에 발생해야합니다. 지금 당분간 프로그램이 멈추고 모든 정보가 동시에 나타납니다. –

+0

내 대답 좀 봐주세요. 확실히 도움이 될 것입니다. –

답변

1

Dispatcher.BeginInvoke는 Dispatcher의 스레드에서 메소드를 호출하도록 신호를 보냅니다. 그러나 메인 스레드가 작업을 잠근 동안 발생하지 않기 때문에 기본적으로 포스트 메시지와 같습니다. 주 스레드를 다시 사용할 수있게 될 때까지는 값을 변경하더라도 UI가 시각적으로 업데이트되지 않습니다.

배경 스레드에서 작업을 수행해야합니다.

하지만 UI를 업데이트하려면 UI의 주 스레드에서 업데이트해야합니다. 이것은 WPF의 제한 사항입니다. 이것이 귀하가 Dispatcher로 이동 한 이유입니다. 나는 당신의 작품이 이미 배경 스레드에 있다고 가정합니다.

스레드를 만들려면 Thread.Start을 사용하여 수행 할 대리자를 전달합니다. 익명 대리자 또는 람다를 사용하는 경우 스택의 변수를 참조 할 수 있지만 대리자가 종료 될 때까지 유지됩니다. 따라서 익명의 대리자에서 참조 변수를 사용할 수 없습니다.

Backgroundworker는 특수한 유형의 백그라운드 스레드입니다. 작업자 스레드의 기대치를 자동화 (완료를 알리고 진행 상황을 업데이트)하지만, 사용자가 없어도 동일한 결과를 얻을 수 있습니다.

스레드 프로세스 중에 UI를 업데이트하려면 해당 스레드가 기본 UI 스레드에 액세스 할 수 있어야합니다. Dispatcher를 전달하거나 익명의 대리자 외부의 Dispatcher를 참조하거나 Dispatcher가 포함 된 개체를 참조하여이 작업을 수행 할 수 있습니다. 모든 스레드의 모든 개체에서 값을 읽을 수 있으므로 다른 스레드의 UIElement로 디스패처에 액세스하는 것이 좋습니다.

UI를 업데이트하려면 수행 할 작업이 수반되는 대리인이있는 Dispatcher.BeginInvoke으로 전화하십시오.

여기

class TestProgress 
{ 
    ProgressBar _ProgressBar; 

    void DoWork() 
    { 
     var worker = (Action)(() => 
     { 
      int progress = 0; 
      // do stuff, delta is change in progress 
      progress += delta; 
      _ProgressBar.Dispatcher.BeginInvoke((Action)(() => 
      { 
       _ProgressBar.Value = progress; 
      })); 
     }); 
     Thread.Start(worker); 
    } 
} 
+0

두 답이 모두 우수했습니다. 둘 다 선택할 수 있기를 바랍니다. Stangely만큼, 내 DoWork 메소드에 Thread.Sleep (1)을 포함하지 않으면 디스플레이가 업데이트되지 않습니다. 백그라운드에서 실행되며 UI를 이동할 수 있지만 동적으로 업데이트되지는 않습니다. –

+1

BeginInvoke 대신 Invoke를 시도하십시오 –

+0

그게 다야! 나는 멀티 스레딩에 대해 많이 기대하고있다. 고맙습니다. –