进度条不移动(WinForms,.Net和BackgroundWorker)

时间:2018-02-09 13:03:52

标签: c# .net winforms progress-bar

简介

我正在尝试使用WinForms制作.Net应用。

我正在使用教程from here展示BackgroundWorkerProgressBar整合。

我在表单中添加了ProgressBarBackgroundWorker控件。 名称与示例中的名称相同。另外,我为WorkerReportProgressTrue属性设置为BackgroundWorker。没有显示错误,项目编译成功......

问题

问题是 - 进度条不移动。 然而,当手动点击时它会移动...... progressBar1.PerformStep();

我缺少什么?

代码

Form1.cs的

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            // Start the BackgroundWorker.
            BackgroundWorker1.RunWorkerAsync();
        }

        private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 100; i++)
            {
                // Wait 500 milliseconds.
                Thread.Sleep(500);
                // Report progress.
                BackgroundWorker1.ReportProgress(i);
            }
        }

        private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Change the value of the ProgressBar to the BackgroundWorker progress.
            progressBar1.Value = e.ProgressPercentage;
            // Set the text.
            this.Text = e.ProgressPercentage.ToString();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            progressBar1.PerformStep();
        }
    }
}

更新

progressBar1.PerformStep();DoWork移除了ProgressChanged。 问题仍然存在(ProgressBar不会移动)。

感谢您提出的建议,我们将在周一进行更多调查。

2 个答案:

答案 0 :(得分:1)

确定已将事件处理程序附加到ProgressChangedDoWork后:

  1. progressBar1.PerformStep()事件处理程序中删除DoWork
  2. 然后在progressBar1.Value = e.ProgressPercentage;事件处理程序中使用ProgressChanged

答案 1 :(得分:0)

几年前我写了一个带有Progress条形码的简单多线程。希望它可以帮到你:

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion

通常在从Alterante线程编写UI元素时,您必须使用Invoke。 BackgroundWorker非常好,并且在创建它的线程上调用“ReportProgress”和“RunWorkerCompleted”事件(应该是GUI线程),所以你不必处理多线程盘旋的那部分。

它也足以捕获通常会逃避DoWork并被吞噬的任何异常,并在完成事件Args中将它们暴露给您。吞咽异常是多线程的一个大问题。

核心问题是,你的循环因异常而中断。在内部调用progressBar1.PerformStep(); DoWork事件必须抛出“CrossThreadException”。 BackgroudnWorker立即完成(由于例外)。当我只是初始值时,会触发RunWorker completed事件。