2010-04-09 102 views
3

我已經寫了一個應用程序,將兩個文件夾同步到一起。該程序的問題在於它在複製文件時停止響應。快速搜索堆棧溢出告訴我,我需要使用稱爲後臺工作者的東西。我已經在網上閱讀了幾頁關於此的內容,但是由於我對編程很陌生,所以很難理解。我怎樣才能簡單地將所有的File.Copy(....)命令放入他們自己的後臺工作器中(如果這甚至是它的工作原理)?下面是運行子過程的按鈕單擊事件代碼和我希望在所有File.Copy行上使用後臺工作程序的子過程。無法讓我的頭在.NET中的後臺工作人員

任何幫助將大大讚賞,因爲在此之後,程序會幾乎完成:d

編輯

使用德維爾的意見,但是,下面我不斷收到follwoing錯誤,我已經改變了我相應的代碼:

錯誤CS1061:類型Gtk.ProgressBar' does not contain a definition for InvokeRequired '沒有擴展方法InvokeRequired' of type Gtk.ProgressBar' 可以找到(是否缺少using指令或程序集引用?)(CS1061)(SYNC-GUI V2)

錯誤CS1061:Gtk.ProgressBar' does not contain a definition for類型的BeginInvoke '和沒有擴展方法BeginInvoke' of type Gtk.ProgressBar' 可以找到(是否缺少using指令或程序集引用?)(CS1061)(SYNC-GUI V2)

下面是我的碼。

按鈕單擊事件:

protected virtual void OnBtnSyncClicked (object sender, System.EventArgs e) 
{ 
    //sets progress bar to 0 
    prgProgressBar.Fraction = 0; 

    //resets values used by progressbar 
    dblCurrentStatus = 0; 
    dblFolderSize = 0; 

    //tests if user has entered the same folder for both target and destination 
    if (fchFolder1.CurrentFolder == fchFolder2.CurrentFolder) 
    { 
     //creates message box 
     MessageDialog msdSame = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, "You cannot sync two folders that are the same"); 
     //sets message box title 
     msdSame.Title="Error"; 
     //sets respone type 
     ResponseType response = (ResponseType) msdSame.Run(); 
     //if user clicks on close button or closes window then close message box 
     if (response == ResponseType.Close || response == ResponseType.DeleteEvent) { 
      msdSame.Destroy(); 
     } 
     return; 
    } 

    //tests if user has entered a target folder that is an extension of the destination folder 
    // or if user has entered a desatination folder that is an extension of the target folder 
    if (fchFolder1.CurrentFolder.StartsWith(fchFolder2.CurrentFolder) || fchFolder2.CurrentFolder.StartsWith(fchFolder1.CurrentFolder)) 
    { 
     //creates message box 
     MessageDialog msdContains = new MessageDialog(this, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, "You cannot sync a folder with one of its parent folders"); 
     //sets message box title 
     msdContains.Title="Error";   
     //sets respone type and runs message box 
     ResponseType response = (ResponseType) msdContains.Run(); 
     //if user clicks on close button or closes window then close message box 
     if (response == ResponseType.Close || response == ResponseType.DeleteEvent) 
     { 
      msdContains.Destroy(); 
     } 
     return; 
    } 

    //creates background worker 
    BackgroundWorker bwBackgroundWorker = new BackgroundWorker(); 
    bwBackgroundWorker.DoWork += new DoWorkEventHandler(bwBackgroundWorkerDoWorkFolder1); 
    //starts background worker 
    bwBackgroundWorker.RunWorkerAsync(); 

    //informs user process is complete 
    prgProgressBar.Text = "Finished"; 
} 

背景工人做工作事件:

private void bwBackgroundWorkerDoWorkFolder1 (object sender, DoWorkEventArgs e) 
{ 
    //Gets total file size of folder 1 
    TotalFileSizeFolder1(fchFolder1.CurrentFolder); 
    //Syncs folder 1 
    SyncFolder1(fchFolder1.CurrentFolder, fchFolder2.CurrentFolder); 
} 

TotalFileSizeFolder1子程序:

protected void TotalFileSizeFolder1 (string strCurrentDirectory) 
{ 
    //inform user that file sizes are being gathered 
    if (prgProgressBar.InvokeRequired) 
    { 
     prgProgressBar.BeginInvoke(new MethodInvoker(delegate {prgProgressBar.Text="Getting total size of " + strCurrentDirectory;})); 
    } 

    //string array of all the directories in directory 
    string[] staAllDirectories = Directory.GetDirectories(strCurrentDirectory); 
    //string array of all the files in directory 
    string[] staAllFiles = Directory.GetFiles(strCurrentDirectory); 

    foreach (string strFile in staAllFiles) 
    { 
     //saves new file info called FileSize 
     FileInfo FileSize = new FileInfo(strFile); 
     //adds file size 
     dblFolderSize = dblFolderSize + FileSize.Length; 
     //pulses progress bar to indicate some movement 
     if (prgProgressBar.InvokeRequired) 
    { 
     prgProgressBar.BeginInvoke(new MethodInvoker(delegate {prgProgressBar.Pulse();})); 
    } 

    } 


    foreach (string strDirectory in staAllDirectories) 
    { 
     TotalFileSize(strDirectory); 
    } 
    //delete text from progress bar 

    if (prgProgressBar.InvokeRequired) 
    { 
     prgProgressBar.BeginInvoke(new MethodInvoker(delegate {prgProgressBar.Text="";})); 
    } 

} 

SyncFolder1子程序:

protected void SyncFolder1 (string strFolder1, string strFolder2) 
{ 
    //string array of all the directories in directory 
    string[] staAllDirectories = Directory.GetDirectories(strFolder1); 
    //string array of all the files in directory 
    string[] staAllFiles = Directory.GetFiles(strFolder1); 

    //loop over each file in directory 
    foreach (string strFile in staAllFiles) 
    { 
     //string of just the file's name and not its path 
     string strFileName = System.IO.Path.GetFileName(strFile); 
     //string containing directory in target folder 
     string strDirectoryInsideFolder1 = System.IO.Path.GetDirectoryName(strFile).Substring(strFolder1.Length); 

     //inform user as to what file is being copied 
     if (prgProgressBar.InvokeRequired) 
     { 
      prgProgressBar.BeginInvoke(new MethodInvoker(delegate {prgProgressBar.Text="Syncing " + strFile;})); 
     } 

     //tests if file does not exist in destination folder 
     if (!File.Exists(fchFolder2.CurrentFolder + "/" + strDirectoryInsideFolder1 + "/" + strFileName)) 
     { 
      //if file does not exist copy it to destination folder, the true below means overwrite if file already exists 
      File.Copy (strFile, strFolder2 + "/" + strDirectoryInsideFolder1 + "/" + strFileName, true); 
     } 

     //tests if file does exist in destination folder 
     if (File.Exists(strFolder2 + "/" + strDirectoryInsideFolder1 + "/" + strFileName)) 
     { 
      //long (number) that contains date of last write time of target file 
      long lngFolder1FileDate = File.GetLastWriteTime(strFile).ToFileTime(); 
      //long (number) that contains date of last write time of destination file 
      long lngFolder2FileDate = File.GetLastWriteTime(strFolder2 + "/" + strDirectoryInsideFolder1 + "/" + strFileName).ToFileTime(); 

      //tests if target file is newer than destination file 
      if (lngFolder1FileDate > lngFolder2FileDate) 
      { 
       //if it is newer then copy file from target folder to destination folder 
       File.Copy (strFile, strFolder2 + "/" + strDirectoryInsideFolder1 + "/" + strFileName, true); 
      } 
     } 
     //gets current file size 
     FileInfo FileSize = new FileInfo(strFile); 
     //sets file's filesize to dblCurrentStatus and adds it to current total of files 
     dblCurrentStatus = dblCurrentStatus + FileSize.Length; 
     double dblPercentage = dblCurrentStatus/dblFolderSize; 
     if (prgProgressBar.InvokeRequired) 
     { 
      prgProgressBar.BeginInvoke(new MethodInvoker(delegate {prgProgressBar.Fraction = dblPercentage;})); 
     } 
    } 

    //loop over each folder in target folder 
    foreach (string strDirectory in staAllDirectories) 
    { 
     //string containing directories inside target folder but not any higher directories 
     string strDirectoryInsideFolder1 = strDirectory.Substring(strFolder1.Length); 
     //tests if directory does not exist inside destination folder 
     if (!Directory.Exists(strFolder2 + "/" + strDirectoryInsideFolder1)) 
     { 
      //it directory does not exisit create it 
      Directory.CreateDirectory(strFolder2 + "/" + strDirectoryInsideFolder1); 
     } 
     //run sync on all files in directory 
     SyncFolders(strDirectory, strFolder2); 
    } 

} 
+1

不要忘記考慮它對您的用戶界面的影響。偶爾檢查BackgroundWorker是否仍在運行(在UI線程上有一個System.Windows.Forms.Timer),以及何時完成,讓用戶知道UI。你會同時允許多個後臺任務嗎?長期來看,應該考慮如何處理後臺線程中的錯誤並告知用戶。 – 2010-04-09 14:06:31

回答

7

初始化您的後臺工作對象

BackgroundWorker bw = new BackgroundWorker(); 
bw.DoWork += new DoWorkEventHandler(bw_DoWork); 

使用此代碼

bw.RunWorkerAsync(); // Calls the bw_DoWork method 

//runs SyncTarget procedure  
SyncTarget(fchTarget.CurrentFolder); 
//gets folder size of destination folder    
FileSizeOfDestination(fchDestination.CurrentFolder);    

的地方定義的DoWork方法

private void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    SyncTarget(fchTarget.CurrentFolder); 
    FileSizeOfDestination(fchDestination.CurrentFolder); 
} 

我不認爲在這裏使用兩個後臺工作人員是必要的,因爲這兩種方法都涉及IO操作。

你也可以很好地利用RunWorkerCompleted和ProgressChanged

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

而且我也看到你訪問的UI元素在你的SyncTarget方法。你不能從另一個線程訪問你的UI元素。你必須使用BeginInvoke方法來完成這項

if (prgProgressBar.InvokeRequired) 
{ 
    prgProgressBar.BeginInvoke(new MethodInvoker(delegate { prgProgressBar.Text="Syncing " + strFile; })); 
} 

您也可以做到這一點使用dispatcher

Dispatcher UIDispatcher = Dispatcher.CurrentDispatcher; // Use this code in the UI thread 

UIDispatcher.Invoke(DispatcherPriority.Normal, new Action(() => 
{ 
    // access your prgProgressBar here 
})); 

對於調度程序和跨線程操作,SO中存在很多問題。你可以瀏覽它們。

我用prgProgressBar作爲例子。但我建議你在ProgressChanged方法中使用進度條。

bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); 

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    prgProgressBar.Value = e.ProgressPercentage; 
} 
+0

嗨我已經設置我的程序使用後臺工作人員,並使用您提到的if語句與後臺工作人員的進度條對話,但是所有if語句都會出現以下兩個錯誤: – Connel 2010-04-14 12:35:47

+0

錯誤CS1061:類型'Gtk.ProgressBar'不包含'InvokeRequired'的定義,並且沒有找到'Gtk.ProgressBar'類型的擴展方法'InvokeRequired'(你是否缺少使用指令或程序集引用?)(CS1061)(Sync- GUI v2) 和 和 錯誤CS1061:類型'Gtk.ProgressBar'不包含'BeginInvoke'的定義,並且沒有找到'Gtk.ProgressBar'類型的擴展方法'BeginInvoke'(你是否缺少using指令或者一個程序集引用?)(CS1061)(Sync-GUI v2) – Connel 2010-04-14 12:54:24

+1

檢查我的答案。我使用調度程序代碼和ProgressChanged方法更新了它。您可以更好地使用完成BackgroundWorker類需求含義的ProgressChanged方法。 – Amsakanna 2010-04-14 14:37:48

2

創建一個BackgroundWorker對象,併爲DoWork事件放入要在後臺運行的所有代碼。然後,當您需要使用它時,請在對象上調用RunWorkerAsync()。

+0

在這一點上不要過多考慮它。做到這一點,然後當它運行並調試項目。在worker方法中設置斷點並使用您的Threads窗口查看單獨運行的UI線程和工作線程。你可以來回切換(UI線程可能在框架中,可能旋轉消息泵)。 – Will 2010-04-09 13:13:53