2011-04-01 71 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