简体   繁体   English

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

[英]Progressbar does not move (WinForms, .Net and BackgroundWorker)

Introduction 介绍

I am trying to make a WinForms app using .Net . 我正在尝试使用.Net制作WinForms应用程序。

I am using tutorial from here wich shows BackgroundWorker and ProgressBar integration. 我正在使用从这里开始的教程该教程显示了BackgroundWorkerProgressBar集成。

I added ProgressBar and BackgroundWorker controls to the form. 我向表单添加了ProgressBarBackgroundWorker控件。 The names are the same as in example. 名称与示例中的相同。 Additionaly, i set WorkerReportProgress property to True for BackgroundWorker . Additionaly,我设置WorkerReportProgress属性为TrueBackgroundWorker No errors are shown and project compiles sucessfully... 没有错误显示,项目成功编译...

Problem 问题

The problem is - progressbar does not move. 问题是-进度栏不会移动。 And yet, it moves when clicked manually... progressBar1.PerformStep(); 但是,当手动单击时它会移动... progressBar1.PerformStep(); .

What am i missing? 我想念什么?

Code

Form1.cs 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();
        }
    }
}

Update 更新

Removed progressBar1.PerformStep(); 删除了progressBar1.PerformStep(); from DoWork and ProgressChanged . 来自DoWorkProgressChanged Still the problem persists (ProgressBar does not move). 问题仍然存在(ProgressBar不会移动)。

Thank you for ideas so far, will look into it more on Monday. 到目前为止,谢谢您的想法,我们将在星期一进行更多探讨。

After you made sure you attached the event handlers to ProgressChanged and DoWork : 确保将事件处理程序附加到ProgressChangedDoWork

  1. Remove progressBar1.PerformStep() from DoWork event handler. DoWork事件处理程序中删除progressBar1.PerformStep()
  2. Then use just progressBar1.Value = e.ProgressPercentage; 然后只使用progressBar1.Value = e.ProgressPercentage; in ProgressChanged event handler. ProgressChanged事件处理程序中。

I wrote a simple Multithreading with Progress bar code a few years back. 几年前,我写了一个带有进度条码的简单多线程。 Hope it helps you: 希望它可以帮助您:

#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

Normally when writing a UI Element from a Alterante Thread, you have to use Invoke . 通常,当从Alterante线程编写UI元素时,必须使用Invoke BackgroundWorker is nice and Invoking the "ReportProgress" and "RunWorkerCompleted" Events on the thread that created it (wich should be the GUI thread) so you do not have to deal with that part of Multithreading wonkyness yet. BackgroundWorker很不错,可以在创建它的线程(应该是GUI线程)上调用“ ReportProgress”和“ RunWorkerCompleted”事件,因此您不必处理多线程处理的那部分。

It is also nice enough to catch any Exceptions that would normally escape DoWork and be swallowed, exposing them to you in the Completed Event Args. 它也足以捕获通常会逃避DoWork并被吞下的所有异常,并在Completed Event Args中向您公开。 Swallowing Exceptions is a huge issue with Multithreading. 吞咽异常是多线程的一个巨大问题。

The core issue is, that your loop breaks due to a Exception. 核心问题是循环由于异常而中断。 Calling progressBar1.PerformStep(); 调用progressBar1.PerformStep(); inside the DoWork Event has to throw a "CrossThreadException". 里面的DoWork的事件不得不抛出一个“CrossThreadException”。 The BackgroudnWorker finishes (due to an exception) instantly. BackgroudnWorker立即完成(由于异常)。 The RunWorker completed event is triggered when i was just the initial value. 当我只是初始值时,将触发RunWorker完成事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM