Apichart Thanomkiet
Apichart Thanomkiet

Reputation: 148

BackgroundWorker OnProgressChanged still fired after RunWorkerCompleted fired

My application used BackgroundWorker for uploading a file to FTP server. Everything works ok but it seems OnProgressChanged event does not work as the way it should be.

I though that OnProgressChanged will completely finish after RunWorkerCompleted event fired, but it's not.

In my case, OnProgressChanged event is still firing though the RunWorkerComplete is fired. Obviously, my progress bar is still moving on while my file is already sent completely to the ftp server.

I tested on my debugging mode and I see that after RunWorkerCompleted Fired, OnPorgressChanged is still working.

My code is here.

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

Any ideas on this issues? Thanks guys

Upvotes: 2

Views: 1205

Answers (1)

Hans Passant
Hans Passant

Reputation: 941357

This is most likely caused by an artifact introduced by the Vista update for the native progress bar component, also present in Windows 7. To see it, start a new Winforms project and drop a progress bar and a button on a form. Double click the button and make the Click event handler look like this:

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

Press F5 and click the button. Note how the bar is animated, it smoothly moves from 0 to 100. Takes about a second.

Perhaps you see the implication now, this animation produces lag. In other words, the visible value is always less than the programmed Value unless you give it enough time to catch up. You don't, you're constantly updating the value with your ProgressChanged event handler.

Unfortunately, they forgot to provide an option to turn this animation off. There's a trick however, the animation is disabled by default for decrements. What you can do is set the Value property twice, first to value+1, then to value. The bar instantly jumps to the programmed value. The only flaw with it is that you can't easily jump to 100%.

Upvotes: 7

Related Questions