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

puruo6ea  于 2023-03-19  发布在  .NET
关注(0)|答案(2)|浏览(165)

简介

我正在尝试使用.Net制作WinForms应用程序。
我正在使用教程from here,其中显示了BackgroundWorkerProgressBar集成。
我向窗体添加了ProgressBarBackgroundWorker控件。名称与示例中的名称相同。此外,我将BackgroundWorkerWorkerReportProgress属性设置为True。没有显示错误,项目编译成功。

问题

问题是- ProgressBar不会移动。然而,当手动点击时,它会移动。
我错过了什么?
编号

  • 表格1.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();
        }
    }
}

更新

已从DoWorkProgressChanged中删除progressBar1.PerformStep();。问题仍然存在(进度栏不移动)。
谢谢你的想法,到目前为止,将在星期一进一步研究。

2exbekwf

2exbekwf1#

确保将事件处理程序附加到ProgressChangedDoWork之后:
1.从DoWork事件处理程序中删除progressBar1.PerformStep()
1.然后在ProgressChanged事件处理程序中仅使用progressBar1.Value = e.ProgressPercentage;

eivnm1vs

eivnm1vs2#

几年前,我写了一个简单的多线程进度条码。希望它能帮助你:

#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很好,并在创建它的线程(应该是GUI线程)上调用“ReportProgress”和“RunWorkerCompleted”事件,因此您还不必处理多线程的那部分问题。
捕捉任何异常也是很好的,这些异常通常会逃脱DoWork并被吞掉,并在Completed Event Args中将它们暴露给您。吞掉异常是多线程的一个大问题。
核心问题是,你的循环会因为一个异常而中断。在DoWork事件**内部调用progressBar1.PerformStep();**必须抛出一个“CrossThreadException”。BackgroundnWorker会立即结束(由于一个异常)。RunWorker completed事件会在i为初始值时触发。

相关问题