Фоновая операция и блокировка основной формы - PullRequest
0 голосов
/ 08 октября 2010

Вот мой сценарий: на форме у меня есть список директорий, кнопка и элемент управления для отображения многострочного текста.В цикле я пытаюсь найти все файлы в каждом каталоге и удалить их.Когда файл удален, я хочу добавить текст в многострочное управление.Моя проблема в том, что при добавлении текста я больше ничего не могу сделать.Форма заблокирована, и если я попытаюсь сделать что-нибудь, она просто перестает отвечать.Файлы удаляются с помощью BackgroundWorker

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
//this is datatable with directories and other info
        MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE = e.Argument as MainDataset.CZYSZCZENIEDataTable;
        CzyscPliki(CZYSZCZENIE, ReportProgress);
    }

private void CzyscPliki(MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE, ReportProgressDel del)
    {
        DirectoryInfo dir = null;
        FileInfo[] files = null;
        bool subfolder = false;
        string katalog = "";
        string maska = "";
        string[] maski = null;
        long total=0;

        string dirS;
        string fileS;
        long fileLen;
//foreach directory to delete
        foreach (DataRow r in CZYSZCZENIE.Rows)
        {
//CanRead - check if row is not deleted or detached
//r["CZYSC"].AsBool() - check if directory should be cleared
            if (r.CanRead() && r["CZYSC"].AsBool())
            {
                subfolder = r["PODKATALOGI"].AsBool();
                katalog = r["KATALOG"].AsString().TrimEnd('\\');
                maska = r["MASKA"].AsString();
                if (maska.IsEmpty())
                    maska = "*";
                maski = maska.Split(';');
                dir = new DirectoryInfo(katalog);
                if (dir.Exists)
                {
                    foreach (string s in maski)
                    {
                        files = dir.GetFiles(s, (subfolder ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly));
                        dir.GetFiles();
                        foreach (FileInfo f in files)
                        {
                            dirS = f.Directory.FullName;
                            fileS = f.Name;
                            fileLen = f.Length;
                            try
                            {
                                f.Delete();
                                total += fileLen;
                                if (del != null)
//here is problem: del - delegate to report state
//when it is called it blocks form
                                    del(dirS, fileS, fileLen, total);

                            }
                            catch (Exception ex) 
                            { }
                        }
                    }
                }
            }
        }
    }
//this is the delegate that appends text in multiline control
//memoEdit1 is the control
//ceReportProgress.Checked - check if report should be added
private void ReportProgress(string directory, string file, long size, long totalSize)
    {
        if (memoEdit1.InvokeRequired)
        {
            memoEdit1.BeginInvoke(new Action<string, string, long, long>(ReportProgress), directory, file, size, totalSize);
        }
        else
        {
            if (ceReportProgress.Checked)
            {
                if (file.IsEmpty())
                    memoEdit1.AppendText("\r\nCzyszczenie katalogu " + directory);
                else
                {
                    memoEdit1.AppendText(file);
                    if (size > 0)
                    {
                        if (size > 1048576)
                        {
                            decimal d = size / 1048576;
                            d = decimal.Round(d, 2);
                            memoEdit1.AppendText("\tWielkość : " + d.AsString() + " megabajtów", false);
                        }
                        else if (size > 1024)
                        {
                            decimal d = (decimal)size / (decimal)1024;
                            d = decimal.Round(d, 2);
                            memoEdit1.AppendText("\tWielkość : " + d.AsString() + " kilobajtów", false);
                        }
                        else
                            memoEdit1.AppendText("\tWielkość : " + size.AsString() + " bajtów", false);
                    }
                    if (totalSize > 0)
                    {
                        if (totalSize > 1073741824)
                        {
                            decimal d = (decimal)totalSize / (decimal)1073741824;
                            d = decimal.Round(d, 2);
                            memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " gigabajtów");
                        }
                        else if (totalSize > 1048576)
                        {
                            decimal d = (decimal)totalSize / (decimal)1048576;
                            d = decimal.Round(d, 2);
                            memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " megabajtów");
                        }
                        else if (totalSize > 1024)
                        {
                            decimal d = (decimal)totalSize / (decimal)1024;
                            d = decimal.Round(d, 2);
                            memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " kilobajtów");
                        }
                        else
                            memoEdit1.AppendText("Zwolniono dotychczas : " + totalSize.AsString() + " bajtów");
                    }
                }
//scroll to the end of control
                memoEdit1.ScrollToEnd();
            }
        }
    }

Как я могу улучшить это, чтобы не блокировать форму?

Ответы [ 2 ]

2 голосов
/ 08 октября 2010

Вы слишком часто вызываете ReportProgress.Делайте это более 1000 раз в секунду, и поток пользовательского интерфейса будет заполнен запросами, которые он не сможет удовлетворить.Он не сможет выполнять свои обычные обязанности, включая рисование элементов управления и реагирование на мышь и клавиатуру.Это выглядит замороженным.Это ухудшается, когда код обновления пользовательского интерфейса становится дороже, обновление текста в TextBox, когда в нем уже много текста, может быть довольно медленным.BGW перестает работать, работает над очисткой журнала невыполненных работ в очереди запросов на вызов, а затем внезапно возвращается в живое состояние, когда очередь наконец очищается.Никогда не имеет смысла называть это чаще, чем раз в 50 миллисекунд, человек не может почувствовать разницу за этим.Соберите информацию в List <>, чтобы вы могли гораздо реже запускать BeginInvoke ().Это все еще не является полной гарантией, если ваш работник может производить результаты быстрее, чем поток пользовательского интерфейса мог бы успеть.В этом случае замедление рабочего было бы исправлением.Легко, используя Invoke вместо BeginInvoke.

0 голосов
/ 08 октября 2010

Если этот работник работает асинхронно, то у вас может быть форма, которая отвечает вам.

Кроме того, проблемы:

  1. Вы запускаете цикл в другомфункция - делает операцию не отвечающей.

  2. Вы даже не проверяете, хочет ли пользователь отменить (просто точку, которую я хотел сделать) - Обрабатывать DoWorkEventArgs '* Cancel свойство внутри цикла foreach.

Переместите код функции CzyscPliki в backgroundWorker1_DoWork (в любом случае он слишком мал).

РЕДАКТИРОВАТЬ:

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

...