Метод на BackgroundWorker замораживает графический интерфейс - PullRequest
1 голос
/ 01 апреля 2011

Я пытаюсь запустить метод, который получает список файлов из указанных папок и представляет его в DataGridView.Метод запускается в BackgroundWorker, поэтому я ожидаю, что графический интерфейс останется активным.Но это все еще замерзает.Вот пример:

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());  
}

Ответы [ 5 ]

3 голосов
/ 22 июля 2011

Не обновляйте событие reportprogress в каждой строке цикла. Вместо этого вызывайте ReportProgress каждые 2 и более итераций (лучший способ - вычислить и шаг, чтобы не обновлять каждую строку, если у вас есть 200000) И заполните сетку, когда весь процесс завершится (в завершенном событии), чтобы обновить все строки. Я думаю, что прогресс предназначен для обновления только прогресса, а не для заполнения группы данных в элементе управления, но я могу ошибаться: от здесь :

Советы Вы, вероятно, знаете больше, чем думаете о BackgroundWorker учебный класс. У BackgroundWorker есть имя, которое может указывать, что оно более сложнее, чем на самом деле. Есть еще много деталей о потоках и прервать вызовы, но как только вы поймете, что BackgroundWorker просто структурное «наложение» на потоки в Windows Forms, это вполне интуитивный. Вот снова шаги:

Сначала вызовите RunWorkerAsync с аргументом. Вы можете передать любой аргумент к этому методу на BackgroundWorker, в том числе ноль. Это просто должно наследовать от объекта, который все делает.

Во-вторых, выполняется пользовательская обработка. Ваш дорогой код выполняется в метод DoWork. Вставьте паузу здесь, так как ваша программа делает это расчеты.

В-третьих, это заканчивается. Когда ваша обработка закончится, RunWorkerCompleted называется. В этом методе вы получите результат. Таким образом, ваш Объект BackgroundWorker изменяет объект в другом потоке, и вы получите это, когда это будет сделано.

Я думаю, что он зависает, когда требуется слишком много обновлений за короткое время, и даже вызов Apllication.DoEvents () не работает все время. Я надеюсь, что это поможет, немного поздно, я знаю, но это лучше, чем никогда;)

1 голос
/ 01 апреля 2011

Возможно, потому что вы блокируете самого фонового работника.

В вашем методе DoWork

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

Обычно вы должны иметь доступ к bckgrFileScanner из вашего метода DoWork и просто вызывать его напрямую какbckgrFileScanner.ReportProgress (.... ....)

При передаче, как и вы, теперь он будет сообщать о прогрессе в фоновом рабочем потоке, который теперь не совпадает с потоком пользовательского интерфейса.(кому принадлежит bckgrFileScanner)

Редактировать Чтобы уточнить:

  1. Ваш поток пользовательского интерфейса владеет bckgrFileScanner и запускает RunWorkerAsync ()
  2. Что происходитв DoWork теперь на собственной ветке.
  3. Поток DoWork «крадет» переменную bckgrFileScanner
  4. Теперь ReportProgress запускается в потоке DoWork вместо потока UIs
1 голос
/ 01 апреля 2011

Этот (упрощенный) пример работает для меня и имеет прекрасный отзывчивый пользовательский интерфейс:

    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()); 
    }

Возможно, это даст вам представление о том, что у вас не так?Возможно, вы захотите попробовать это без сетки данных, просто чтобы попытаться изолировать проблему.

0 голосов
/ 01 апреля 2011

Возможные причины:

Я думаю, вы просто хотите сообщить имя файла:

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

Или список папок в DoWork является элементом управления пользовательского интерфейса:

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

Почему бы не передать список папок методу RunWorkerAsync.

0 голосов
/ 01 апреля 2011

Вы звоните ReportProgress на сканере. Не должно быть, что bckgrFileScanner?

EDIT

Является ли случайно отсканированный список файлов привязанным к пользовательскому интерфейсу? В этом случае изменение списка приводит к обновлению пользовательского интерфейса.

...