BackgroundWorker OnProgressChanged все еще срабатывает после запуска RunWorkerCompleted - PullRequest
2 голосов
/ 11 октября 2011

Мое приложение использовало BackgroundWorker для загрузки файла на FTP-сервер. Все работает нормально, но, похоже, OnProgressChanged событие не работает так, как должно быть.

Я думаю, что OnProgressChanged полностью завершится после события RunWorkerCompleted, но это не так.

В моем случае событие OnProgressChanged все еще запускается, хотя RunWorkerComplete запускается. Очевидно, мой индикатор выполнения все еще движется, в то время как мой файл уже полностью отправлен на FTP-сервер.

Я тестировал свой режим отладки и вижу, что после RunWorkerCompleted Fired OnPorgressChanged все еще работает.

Мой код здесь.

 void FTP_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bw = sender as BackgroundWorker;
        try
        {
            string filename = e.Argument.ToString();
            if (filename != string.Empty)
            { 
                FileInfo fileInf = new FileInfo(filename);
                FtpWebRequest reqFTP;
                if (!IsFolderExist(_defaultDir))
                {
                    MakeDefaultDir(_defaultDir);
                }

                reqFTP = GetRequest(this._host, this._port, GetDirName(_defaultDir) + "/" + fileInf.Name, this._user, this._pass);
                reqFTP.KeepAlive = false;
                reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
                reqFTP.UseBinary = true;
                reqFTP.ContentLength = fileInf.Length;

                long FileSize = fileInf.Length;
                string FileSizeDescription = GetFileSize(FileSize);



                int ChunkSize = 4096, NumRetries = 0, MaxRetries = 50;
                long SentBytes = 0;
                byte[] Buffer = new byte[ChunkSize]; 
                int BytesRead = 0;


                using (Stream requestStream = reqFTP.GetRequestStream())
                {

                    using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                         BytesRead = fs.Read(Buffer, 0, ChunkSize); // read the first chunk in the buffer
                        while (BytesRead > 0)
                        {
                            try
                            {
                                if (bw.CancellationPending)
                                    return;

                                requestStream.Write(Buffer, 0, BytesRead);


                                SentBytes += BytesRead;

                                // Here is progress information
                                string SummaryText = String.Format("Transferred {0} / {1}", GetFileSize(SentBytes), FileSizeDescription);
                                bw.ReportProgress((int)(((decimal)SentBytes / (decimal)FileSize) * 100), SummaryText);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("Exception: " + ex.ToString());
                                if (NumRetries++ < MaxRetries)
                                {
                                    fs.Position -= BytesRead;
                                }
                                else
                                {
                                    throw new Exception(String.Format("Error occurred during upload, too many retries. \n{0}", ex.ToString()));
                                }
                            }
                            BytesRead = fs.Read(Buffer, 0, ChunkSize);  
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (OnFTPError != null)
            {
                OnFTPError(this, "Error was handled in Replaced File Uploading :" + ex.Message);
            }
        }     
    }

Есть идеи по этому вопросу? Спасибо, ребята

1 Ответ

7 голосов
/ 11 октября 2011

Скорее всего, это вызвано артефактом, представленным обновлением Vista для собственного компонента индикатора выполнения, также присутствующим в Windows 7. Чтобы увидеть его, запустите новый проект Winforms и перетащите индикатор выполнения и кнопку на форму. Дважды нажмите кнопку и сделайте обработчик события Click похожим на это:

    private void button1_Click(object sender, EventArgs e) {
        if (progressBar1.Value == progressBar1.Maximum) progressBar1.Value = progressBar1.Minimum;
        else progressBar1.Value = progressBar1.Maximum;
    }

Нажмите F5 и нажмите кнопку. Обратите внимание, что полоса анимирована , она плавно перемещается от 0 до 100. Занимает около секунды.

Возможно, вы сейчас видите, что эта анимация приводит к задержке. Другими словами, видимое значение всегда меньше запрограммированного значения, если вы не дадите ему достаточно времени, чтобы наверстать упущенное. Вы не обновляете значение с помощью обработчика событий ProgressChanged.

К сожалению, они забыли предоставить возможность отключить эту анимацию. Однако есть хитрость, по умолчанию анимация отключена для декрементов. Что вы можете сделать, это установить свойство Value дважды, сначала на значение + 1, а затем на значение. Бар мгновенно переходит к запрограммированному значению. Единственный недостаток в том, что вы не можете легко перейти на 100%.

...