【问题标题】:BackgroundWorker OnProgressChanged still fired after RunWorkerCompleted fired在 RunWorkerCompleted 被解雇后,BackgroundWorker OnProgressChanged 仍然被解雇
【发布时间】:2011-10-11 10:07:40
【问题描述】:

我的应用程序使用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);
            }
        }     
    }

对这个问题有什么想法吗? 谢谢大家

【问题讨论】:

  • 这不应该发生。请显示一些代码。
  • 有没有可能后来 OnProgressChanged 的​​提升实际上发生得更早,但是由于主线程忙于其他事情,所以在主线程上被批量处理为消息?
  • @Polity 我对此不确定。但就我而言,在 RunWorkerCompleted 被解雇之前我什么都不做。因此,在这种情况下,我的状态已完全发送,但我的进度条仍在移动。
  • 您的代码会生成多少个 Progress 事件?应该不会超过 100。如果是数万,那么 @Polly 的场景是有道理的。
  • 我确定它不会产生超过 100 个事件

标签: c# progress-bar backgroundworker


【解决方案1】:

这很可能是由 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 属性设置两次,第一次设置为 value+1,然后设置为 value。条形图立即跳至编程值。唯一的缺点是你不能轻易地跳到 100%。

【讨论】:

  • 哦,我以前不知道,你只是让我意识到这件事。谢谢,对了,诀窍就是设置progressbar属性值+1,然后将progressbar值设置为程序值?
  • 您可以通过将进度条的最小值/最大值设为 0/1000 来伪造 100%,然后人眼无法看到 99.9% 和 100.0% 之间的差异。
  • @David - 我的屏幕是 1600 像素宽,仍然相差 1 :) 程序员确实对这样的细节感到疯狂。没错。
  • 我的两个都是1920宽!不寻常的全屏 prog 栏。然后使用 10000。当然这些只是我们看到的细节,用户并不关心!附言这难道不是我向您介绍的有关 Windows 的极少数事物之一吗?!
  • 呵呵,我猜这是我们知识的融合。好东西。
猜你喜欢
  • 1970-01-01
  • 2013-03-25
  • 2018-11-04
  • 2020-03-28
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多