2011-04-01 76 views
1

我想運行一個方法,從指定的文件夾獲取文件列表並在DataGridView中表示它。該方法在BackgroundWorker中運行,因此我期望GUI保持活動狀態。但它仍然凍結。以下是一個示例:BackgroundWorker上的方法凍結GUI

private void startScan_Click(object sender, EventArgs e) 
{ 
    bckgrFileScanner.RunWorkerAsync(); 
} 

private void bckgrFileScanner_DoWork(object sender, DoWorkEventArgs e) 
{ 
//for each folder in list perform this function, which scans folder and gets all files 
    for (int i = 0; i < folderList.Items.Count; i++) 
    { 
     GetFileList(ref scannedFiles, folderList.Items[i].ToString(), bckgrFileScanner); 

    } 
} 

public static void GetFileList(ref List<FileInfo> fList, string fPath, BackgroundWorker scanner)  
{ 
    DirectoryInfo di = new DirectoryInfo(fPath); 
    FileInfo[] fi = di.GetFiles(); 

    foreach (FileInfo fiTemp in fi) 
    {     
      if (fiTemp.Name.StartsWith("~$") == false) 
      { 
       //adds items to list of all scanned files 
       fList.Add(fiTemp); 
       //reports file name to ProgressChanged method 
       scanner.ReportProgress(0, fiTemp); 
      } 
    } 
    DirectoryInfo[] dFolders = di.GetDirectories(); 

    //use recursion for all subfolders 
    foreach (DirectoryInfo d in dFolders) 
    { 
      GetFileList(ref fList, d.FullName, scanner); 
    } 
} 

private void bckgrFileScanner_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    //userstate is filename, so add it to table 
    filesDataGrid.Rows.Add(e.UserState.ToString()); 
} 

回答

0

您在掃描儀上致電ReportProgress。不應該是bckgrFileScanner

編輯

被任何機會scannedFiles列表數據綁定到UI?如果是這樣,對列表的更改會導致UI更新。

+0

在方法GetFileList「掃描儀」是引用bckgrFileScanner,這就是爲什麼我打電話掃描儀insck bckgrFileScanner。此外,在這種方法中,我甚至無法訪問bckgrFileScanner。 – andree 2011-04-01 07:16:11

+0

啊,是的,我錯過了由於橫向滾動。您可以使用Debug.WriteLine(Thread.CurrentThread ...)來跟蹤哪個線程正在執行代碼,以便您可以檢查您的UI線程是否真的被鎖定或其他事情是否被破壞。 – 2011-04-01 07:21:39

+0

我又增加了一個建議。 – 2011-04-01 07:23:55

0

可能的原因:

我覺得你只是想報告的文件名:

//reports file name to ProgressChanged method 
scanner.ReportProgress(0, fiTemp.Name); 

還是folderList在DoWork的是一個UI控件:

for (int i = 0; i < folderList.Items.Count; i++) 
{ 
    GetFileList(ref scannedFiles, folderList.Items[i].ToString(), bckgrFileScanner); 
} 

爲什麼不及格名單的文件夾添加到RunWorkerAsync方法中。

+0

這是真的,我的錯誤。不是凍結的原因。 – andree 2011-04-01 07:32:25

+0

folderList是ListBox,它包含所有文件夾。試圖將文件夾列表項作爲字符串數組傳遞給RunWorkerAsync - 仍然沒有運氣。 – andree 2011-04-01 08:01:16

1

這(簡體),例如對我的作品,並有一個可愛的響應UI:

BackgroundWorker m_objWorker = new BackgroundWorker(); 

    public FormBackgroundWorkerExample() 
    { 
     InitializeComponent(); 
     m_objWorker.WorkerReportsProgress = true; 
     m_objWorker.DoWork += new DoWorkEventHandler(m_objWorker_DoWork); 
     m_objWorker.ProgressChanged += new ProgressChangedEventHandler(m_objWorker_ProgressChanged); 
    } 

    private void btnStart_Click(object sender, EventArgs e) 
    { 
     m_objWorker.RunWorkerAsync(); 
    } 

    private void m_objWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //for each folder in list perform this function, which scans folder and gets all files 
     for (int i = 0; i <= 100; i++) 
     { 
      m_objWorker.ReportProgress(i, "FooBar"); 
      Thread.Sleep(1000); 
     } 
    } 

    private void m_objWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progressBar1.Value = e.ProgressPercentage; 
     dataGridView1.Rows.Add(e.UserState.ToString()); 
    } 

也許這會給你一個想法在那裏你是哪裏錯了?

編輯:您可能想嘗試沒有datagrid只是試圖隔離問題。

+0

我曾在其他方法使用backgroundworker早些時候我在這裏使用相同的風格,它工作得很好。我想也許它與遞歸有關,但在從我的方法中刪除它後,它仍然凍結。 – andree 2011-04-01 07:37:48

+0

不向數據網格添加行它工作正常,沒有凍結,所以問題在那裏,但我不明白爲什麼,因爲我之前使用類似的代碼,其中表是從ProgressChanged更新,沒有凍結被發現在那裏。 – andree 2011-04-01 07:45:13

+0

@andree我更新了示例;向數據網格添加行在這裏沒有問題。是否還有其他可能與您的代碼示例中未包含的相關內容? – firefox1986 2011-04-01 08:01:46

1

可能是因爲你鎖定了背景工作者本身。

在你的DoWork方法

GetFileList(ref scannedFiles, folderList.Items[i].ToString(), bckgrFileScanner); 

Normaly你應該從你的DoWork方法獲得bckgrFileScanner,而直接稱呼其爲bckgrFileScanner.ReportProgress(.... ....)

當像你一樣傳遞它時,它現在會報告後臺工作線程的進度,現在它與UI線程不一樣。 (誰擁有bckgrFileScanner)

編輯澄清:

  1. 你的UI線程擁有bckgrFileScanner和火災的RunWorkerAsync()
  2. 這種情況發生在DoWork的東西現在是在自己的線程。
  3. 的DoWork的線程被「偷」變量bckgrFileScanner
  4. 現在DoWork的線程上ReportProgress火災,而不是用戶界面線程
+0

GetFileList(ref scannedFiles,folderList.Items [i] .ToString(),bckgrFileScanner); 我已經有這一行,但是當使用遞歸時,我調用了掃描器,因爲我沒有訪問getFileList方法內的bckgrFileScanned。對不起,但我真的不明白我需要在這裏更改。 – andree 2011-04-01 08:36:26

+0

是否有任何理由爲什麼你想讓這種方法是靜態的? 使其非靜止並直接使用bckgrFileScanner而不是「scanner.ReportProgress」。 如果你打算使用它作爲其他來源/類的工具,那麼你可以做一些類似於「public static class ScanDirectories {..}」的工作,讓後臺工作者在目錄遍歷那裏,並添加返回完整當它通過一個事件完成時列出。或者(如果您使用wpf/silverlight)將項目添加到ObservableCollection 並聽取有關更改的事件。 – ravndal 2011-04-01 12:43:14

3

在你的循環中的每一行不更新reportprogress事件。 相反,每2次或更多次迭代調用ReportProgress(最好的方法是計算et步驟,如果您有200000,則不更新每行) 並在整個過程完成時(在完成的事件中)填充網格,更新所有行。我認爲進步是爲了更新進度而已,不填一堆數據到控制,但我可能是錯的: 從here

提示你可能知道的比你想想的BackgroundWorker 類。 BackgroundWorker的名稱可能表明它比實際上更復雜。有關線程 和中止調用的更多詳細信息,但是一旦您瞭解到BackgroundWorker只是 是Windows窗體中的線程的結構「覆蓋」,則直觀上就是 。再次執行以下步驟:

首先,使用參數調用RunWorkerAsync。您可以將任何參數 傳遞給BackgroundWorker上的此方法,包括null。它只需要 繼承對象,這一切都是。

其次,自定義處理運行。您的昂貴代碼在 DoWork方法中執行。在您的程序進行 計算時插入暫停。

三,結束。處理完成後,調用RunWorkerCompleted 。在這種方法中,您會收到結果。這樣,您的BackgroundWorker對象會修改另一個線程上的對象,並在您完成後接收它。

我認爲它會在需要短時間內進行太多更新時掛起,甚至調用Apllication.DoEvents()不會一直工作。 我希望它會有所幫助,我知道有點晚,但它總比從未好;)

+0

我已經用一種不同的方式修正了它(帶有分頁功能的小表),不管怎麼說都要打賭。 – andree 2011-07-25 07:52:18