ReportProgress不会使用c#中的任务调用progressChanged

时间:2013-12-13 06:49:49

标签: c# task backgroundworker

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {            
        int currentProgress=-1;

        while (currentProgress<length)
        {
            currentProgress=Worker.progress;
            backgroundWorker1.ReportProgress(currentProgress);
            Thread.Sleep(500);
            length = Worker.UrlList.Count;
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        int ix = e.ProgressPercentage;
        progressBar1.Value = ix;
        lblText.Text =ix+" %";
    }

我写了一个程序,通过阅读文件下载页面源有大约1000个URL。所以我用Tasks来下载异步页面。这里Worker.progress是当前执行的URL数量。虽然debuger击中backgroundWorker1.ReportProgress(currentProgress);,但它永远不会进入backgroundWorker1_ProgressChanged

 private void StartButton_Click(object sender, EventArgs e)
    {            
        t.makeUrlList(inputFile);

        backgroundWorker1 = new BackgroundWorker();
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker1.RunWorkerAsync();
        t.RunTasks();
        Application.Exit();
    }

后台工作人员在启动按钮点击时初始化...

这是创建我的任务的地方....

public void RunTasks()
    {
        if (numOfTasks > UrlList.Count)
            numOfTasks=UrlList.Count-1;
       Task[] t = new Task[numOfTasks];
        int j = 0;
        while ( j < UrlList.Count-1)
        {

           for (int i = 0; (i < t.Count())&&(j<UrlList.Count-1); i++)
            {


                try
                {
                    if (t[i].IsCompleted || t[i].IsCanceled || t[i].IsFaulted)
                    {
                        t[i] = Task.Run(() => FindWIN(j));
                        j++;
                        progress = j;                            
                    }
                }
                catch (NullReferenceException ex)
                {
                    t[i] = Task.Run(() => FindWIN(j));
                    j++;
                    progress = j;
                }
                }
            }
        }

3 个答案:

答案 0 :(得分:3)

如果您希望BackgroundWorker支持更新进度信息,则应将WorkerReportsProgress的值设置为true。如果此属性为true,则用户代码可以调用ReportProgress来启动事件ProgressChanged。

后台工作程序初始化: -

 backgroundWorker1 = new BackgroundWorker();
 backgroundWorker1.WorkerReportsProgress = true;
 backgroundWorker1.DoWork+=backgroundWorker1_DoWork;
 backgroundWorker1.ProgressChanged+=backgroundWorker1_ProgressChanged;
 backgroundWorker1.RunWorkerAsync();

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
            int currentProgress = -1;

            decimal length=1000;
            while (currentProgress < length)
            {
                currentProgress = Worker.progress;
                backgroundWorker1.ReportProgress(currentProgress);
                Thread.Sleep(500);
                length = Worker.UrlList.Count;
            }
 }

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)        {
            int ix = e.ProgressPercentage;
            progressBar1.Value = ix;
            lblText.Text = ix + " %";
}

答案 1 :(得分:2)

在初始化阶段,您应该将worker的WorkerReportsProgress属性设置为true。

答案 2 :(得分:2)

请参阅下面的演示代码。这大多是未经测试的,当然不是生产标准,但它应该会给你一个良好的开端!

  1. 它使用ConcurrentQueue来保存要处理的网址列表。这是线程安全的,让生活更轻松。

  2. 它具有可配置数量的网址和任务。最好不要完成1000个任务,而是拥有一个工作项队列,以及一个较小的任务池,它可以提取项目&#39;离开队列,直到它排空。这意味着您可以对不同数量的任务进行性能测试,并为您的问题找到最佳价值。

  3. 更新进度条时使用Invoke - 这可以避免跨线程异常。

  4. BackgroundWorker - 仅TaskFactoryTask

    public partial class Form1 : Form
    {
        private const int UrlCount = 1000;
        private const int taskCount = 10;
        private ConcurrentQueue<string> urlList;
        private List<Task> taskList;
    
        public Form1()
        {
            InitializeComponent();
        }
    
        private void ResetQueue()
        {
            // fake up a number of strings to process
            urlList = new ConcurrentQueue<string>(Enumerable.Range(0, UrlCount)
                      .Select(i => "http://www." + Guid.NewGuid().ToString() + ".com"));
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            ResetQueue();
            var taskFactory = new TaskFactory();
            // start a bunch of tasks
            taskList = Enumerable.Range(0, taskCount).Select(i => taskFactory.StartNew(() => ProcessUrl()))
                                  .ToList();
        }
    
        void ProcessUrl()
        {
            string current;
    
            // keep grabbing items till the queue is empty
            while (urlList.TryDequeue(out current))
            {
                // run your code
                FindWIN(current);
    
                // invoke here to avoid cross thread issues
                Invoke((Action)(() => UpdateProgress()));
            }
        }
    
        void FindWIN(string url)
        {
            // your code here
            // as a demo, sleep a sort-of-random time between 0 and 100 ms
            Thread.Sleep(Math.Abs(url.GetHashCode()) % 100);
        }
    
        void UpdateProgress()
        {
            // work out what percentage of the queue is processed
            progressBar1.Value = (int)(100 - ((double)urlList.Count * 100.0 / UrlCount));
        }
    }