2009-11-19 29 views
0

我做了this code example,它成功地使用了BackgroundWorker來在for循環中推進進度條。如何從遞歸方法推進進度條,同時避免線程問題?

現在我正在嘗試將它與以下遞歸文件複製方法一起使用,以便它可以顯示覆制到底有多遠,但以下代碼給了我錯誤「此BackgroundWorker當前正忙碌,不能同時運行多個任務。「

我需要改變什麼,以便這種遞歸方法不會得到這些線程問題?

XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <DockPanel LastChildFill="True" HorizontalAlignment="Left" VerticalAlignment="Top" 
       Margin="10"> 

     <TextBlock DockPanel.Dock="Top" Text="{Binding PageTitle}" Style="{DynamicResource PageTitleStyle}"/> 
     <TextBlock DockPanel.Dock="Top" Text="{Binding PageDescription}" Style="{DynamicResource PageDescriptionStyle}"/> 

     <Button x:Name="Button_Start" HorizontalAlignment="Left" DockPanel.Dock="Top" Content="Start Task" Click="Button_Start_Click" Height="25" Width="200"/> 

     <ProgressBar x:Name="ProgressBar" 
        HorizontalAlignment="Left" 
        Margin="0 10 0 0" 
        Height="23" 
        Width="500" 
        Minimum="0" 
        Maximum="100" 
        /> 
    </DockPanel> 
</Window> 

後臺代碼:

using System.Windows; 
using System.ComponentModel; 
using System.Threading; 
using System.IO; 

namespace WpfApplication1 
{ 
    public partial class MainWindow : Window 
    { 
     private BackgroundWorker backgroundWorker; 
     int thread1percentageFinished = 0; 

     private int totalFilesToCopy; 
     private int numberOfFilesCopied; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      ProgressBar.Visibility = Visibility.Collapsed; 
     } 

     private void Button_Start_Click(object sender, RoutedEventArgs e) 
     { 
      int totalFilesToCopy = 1000; 
      int numberOfFilesCopied = 0; 

      backgroundWorker = new BackgroundWorker(); 
      backgroundWorker.WorkerReportsProgress = true; 
      backgroundWorker.WorkerSupportsCancellation = true; 
      ProgressBar.Visibility = Visibility.Visible; 

      CopyFolder(@"C:\test", @"C:\test2"); 
     } 


     void CopyFolder(string sourceFolder, string destFolder) 
     { 
      backgroundWorker.DoWork += (s, args) => 
      { 
       BackgroundWorker worker = s as BackgroundWorker; 
       if (!Directory.Exists(destFolder)) 
        Directory.CreateDirectory(destFolder); 
       string[] files = Directory.GetFiles(sourceFolder); 
       foreach (string file in files) 
       { 
        string name = Path.GetFileName(file); 
        string dest = Path.Combine(destFolder, name); 
        File.Copy(file, dest, true); 
        numberOfFilesCopied++; 
        float percentageDone = (numberOfFilesCopied/(float)totalFilesToCopy) * 100f; 
        worker.ReportProgress((int)percentageDone); 
       } 
       string[] folders = Directory.GetDirectories(sourceFolder); 
       foreach (string folder in folders) 
       { 
        string name = Path.GetFileName(folder); 
        string dest = Path.Combine(destFolder, name); 
        CopyFolder(folder, dest); 
       } 
      }; 

      backgroundWorker.ProgressChanged += (s, args) => 
      { 
       thread1percentageFinished = args.ProgressPercentage; 
       ProgressBar.Value = thread1percentageFinished; 
      }; 


      backgroundWorker.RunWorkerCompleted += (s, args) => 
      { 
       Button_Start.IsEnabled = true; 
       ProgressBar.Visibility = Visibility.Collapsed; 
       ProgressBar.Value = 0; 
      }; 

      backgroundWorker.RunWorkerAsync(); 
     } 



    } 
} 

回答

1

的問題是,你正在調用相同的背景工人的目錄遍歷的每一次迭代。您所需要的只是一名實際完成工作的後臺工作人員。整個遞歸遍歷應包含在對DoWork的單個調用中(而不是每個子目錄掃描)。然後你只需要主UI線程更新你的進度條。

4

實際上最好使用遞歸來查找所需的所有工作,然後設置BackgroundWorker,然後在非遞歸循環中開始工作,根據需要更新進度,然後關閉BackgroundWorker

你這樣做的方式,進度條會跳到所有的地方,你會提供不可靠的反饋給用戶。他們可能會到達一個副本的「末端」,然後突然緩慢下移到一個非常大的文件夾結構中,從而一直推回到開始。

如果您想繼續按照您的方式進行操作,則需要將BackgroundWorker的所有準備工作移至Button_Start_Click方法以及RunWorkerAsync()調用。你保留所有的在CopyFolder本身的現有CopyFolderDoWork定義的「膽」,但到後臺工作的參考,而不是通過:

backgroundWorker.DoWork += (s, args) => 
{ 
    CopyFolder(@"C:\test", @"C:\test2", s); 
}; 

然後你就可以有一個CopyFolder,看起來更像是這樣的:

void CopyFolder(string sourceFolder, string destFolder, BackgroundWorker worker) 
{ 
    if (!Directory.Exists(destFolder)) 
     ... // the rest is unchanged 
} 

這樣,你只創建和啓動了一個BackgroundWorker和剛好路過一個參考下來調用樹。