2016-12-07 1 views
0

Parallel.Foreach을 실행하는 동안 진행률 막대를 업데이트하려고하지만 실행 중에 아무 것도 발생하지 않습니다. Progressbar는 For 루프가 끝날 때만 업데이트됩니다. 이 코드를 어떻게 작동시킬 수 있습니까?WPF : Parallel.Foreach에서 진행률 막대 업데이트

XAML이 답변에서

<StackPanel> 
     <Grid x:Name="LoadProgressGrid" Height="100"     
        Visibility="Visible"> 
      <ProgressBar x:Name="LoadProgress" 
       Maximum="100" 
       Minimum="1" /> 
      <TextBlock Margin="0,0,0,-5" 
       HorizontalAlignment="Center" 
       VerticalAlignment="Center" 
       FontSize="16"><Run Text="Import Progress"/></TextBlock> 
     </Grid> 
     <Button Height="35" Width="100" Margin="0,10" Content="Test" Click="Test_Click"/> 
    </StackPanel> 

C#

private void Test_Click(object sender, RoutedEventArgs e) 
     { 
       decimal current=0; 
       List<string> lst = new List<string>(); 

       lst.Add("Foo"); 
       lst.Add("Foo"); 
       lst.Add("Foo"); 
       lst.Add("Foo"); 

       decimal max = 100000; 

       var uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 

       Parallel.ForEach(lst, (data) => 
       { 
       for (int i = 0; i < max; i++) 
       { 
        // Use the uiFactory above: 
        // Note the need for a temporary here to avoid closure issues! 
        current = current + 1; 
        uiFactory.StartNew(() => LoadProgress.Value = (double)(current/max)*100); 
       } 
       }); 


       MessageBox.Show("Done!"); 
     } 
+0

LoadProgress.Value는 정수가 아니고 정수가 아닌가요? – Vyrira

+2

UI에서 실제로 작업을 수행 할 수있게하려면 UI 스레드를 차단하지 마십시오. – Servy

+0

클로저를 사용하지 않기 위해 임시로 만들지는 않으므로 임시로 만드는 것이 아닙니다. 당신은 단지 클로저를 계속 사용합니다. – Servy

답변

0

: Using Task with Parallel.Foreach in .NET 4.0 및 Servy의 코멘트 내가 작업을 얻었다. 루프는 또한 액세스 해에서 상태를 변경하는 말은 실행되는 스레드, 그리고 당신의 대답에 Servy로 의견을 차단하는 완료 될 때까지

의견에서 지적
private void Test_Click(object sender, RoutedEventArgs e) 
     { 
      test(); 

     } 

     public async void test() 
     { 
      decimal current = 0; 
      List<string> lst = new List<string>(); 

      lst.Add("Foo"); 
      lst.Add("Foo"); 
      lst.Add("Foo"); 
      lst.Add("Foo"); 

      decimal max = 10000; 

      //Remove await (and async from signature) if, want to see the message box rightway. 
      await Task.Run(() => Parallel.ForEach(lst, (data) => 
      { 
       for (int i = 0; i < max; i++) 
       {           
        current = current + 1;      
        Dispatcher.Invoke(new Action(() => LoadProgress.Value = (double)(current/max) * 100)); 
       } 
      })); 

      MessageBox.Show("Done!"); 
     } 
+0

이유 투표? 뭔가 잘못되었거나 끔찍한 일을하고있는 중입니까? 저에게 알려주세요. – teddy2

+0

그래서 스레드 풀 풀을 예약하여 스레드 풀 스레드가 일정한 작업을 실행하여 UI 시작일 때부터 시작하여 스레드를 값으로 설정하도록 예약합니다. 그것은 끔찍한 디자인입니다. 그리고 그것은 unsynchronized 매너 (unsynchronized manor)에있는 다양한 쓰레드 풀 쓰레드들로부터 무효 한 상태로의 접근을 언급하지도 않습니다. – Servy

+0

확인. 응답 해 주셔서 감사합니다. 나는 C#과 작업에 대한 첫 번째 시도로 꽤 새롭다. 친절하게 해결책을 알려줄 수 있습니까? Parallel.ForEach에서 WPF 진행률 막대를 업데이트 할 수 있습니까? – teddy2

2

, Parallel.ForEach는 반환하지 않습니다 동기화 또는 객체 잠금이없는 다양한 스레드 (Race Conditions 참조)

UI 스레드에서 상태를 바꿀 올바른 방법이 확실치 않은 경우 IProgress<T>으로 컨텍스트를 캡처하는 작업을 프레임 워크에서 나가게 할 수 있습니다. 반환 형식 void을 유지하면서 당신의 대답에 대해서는

, 당신은 Test_Click 이벤트 처리기에 직접 async 키워드를 넣을 수 있지만 무효는 다른 async 방법을 권장하거나 제안하지 않는 마음에 베어하시기 바랍니다 그리고 그들은 유형을 반환해야 Task 또는 Task<T>, read more here on why async void is a bad idea.

요점은 여기에 async 코드를 사용하고 진행 상황을보고하고 진행률 표시 줄을 업데이트하는 비 차단 코드입니다. 더 읽기 쉽도록 코드를 주석 처리했습니다.

// Add the async keyword to our event handler 
private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    //Begin our Task 
    Task downloadTask = DownloadFile(); 

    // Await the task 
    await downloadTask; 
} 

private async Task DownloadFile() 
{ 
    // Capture the UI context to update our ProgressBar on the UI thread 
    IProgress<int> progress = new Progress<int>(i => { LoadProgress.Value = i; }); 
    // Run our loop 
    for (int i = 0; i < 100; i++) 
    { 
     int localClosure = i; 
     // Simulate work 
     await Task.Delay(1000); 
     // Report our progress 
     progress.Report((int)((double)localClosure/100 * 100)); 
    } 
} 
관련 문제