How to load the progressbar at the same time my method is running

99封情书 提交于 2021-01-29 19:48:57

问题


I have a long running method, so I created a progress bar to show what percentage my method was to completing, but I am having difficulty figuring out how to do this ,syncing my progress bar with my method => excelHelper.InsertNewRows();.

public void ButtonSubmit_Click(object sender, EventArgs e)
{
    if (isProcessRunning)
    {
        MessageBox.Show("A Process is aleady running");
        return;
    }

    Thread backgroundThread = new Thread(
        new ThreadStart(() =>
        {
            for (int n = 0; n < 100; n++)
            {
                isProcessRunning = true;
                Thread.Sleep(50);
                progressBar1.Invoke(
                    new Action(() =>
                    {
                        progressBar1.Value = n;
                        label3.Text = ("Progress: " + n + "%");
                    }
                 ));
            }
            MessageBox.Show("Thread completed!");
            progressBar1.Invoke(
                new Action(() =>
                {
                    progressBar1.Value = 0;
                }
                ));
            isProcessRunning = false;
        }
        ));
    backgroundThread.Start();
    excelHelper.InsertNewRows();
    var folder = TextOutputFile.Text + @"\" +
    DateTime.Now.ToString("yyyy_MM_dd_") + "SA_Analysis_Report.xlsx";
    excelHelper.Save(folder);
    MessageBox.Show("File has been added to file");
}

回答1:


IMO your problem is, that you dont have any communication between the working thread excelHelper.InsertNewRows(); and your progressbar thread. Both threads are running without any information about the other thread and their progress.

You could rewrite the background thread, so its capable of taking the percentage as a parameter, which is shown in the moment you call the thread.

E.g. Pseudo Code:

public void progressbarThread(int percentage) 
{
    // Invoke the percentage to your progressbar, then terminate this thread
}

public void InsertNewRows() 
{
    // Do something...
    // 10%
    Thread backgroundThread = new Thread(new ThreadStart(() => progressBarThread(10)));
    backgroundThread.Start();
    // Do something...
    // 50%
    Thread backgroundThread = new Thread(new ThreadStart(() => progressBarThread(50)));
    backgroundThread.Start();
    // etc. etc.
}

Update: I've found this on my own research how to build a smooth loadingbar with an extra form, it maybe useful: Form in an extra Thread




回答2:


I use this form class: -

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

namespace Yournamespace
{
    public partial class frmProgressBar : Form
    {
        public Action Worker { get; set; }

        System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();

        public const long MINIMUM_DISPLAY_TIME = 300;    // Minimum time to display the progress bar is 300 milliseconds

        public frmProgressBar(Action worker)
        {
            InitializeComponent();

            if(worker == null)
            {
                throw new ArgumentNullException();
            }

            Worker = worker;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Task.Factory.StartNew(Worker).ContinueWith(t => { this.Close(); }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        protected override void OnClosed(EventArgs e)
        {
            // the code that you want to measure comes here
            watch.Stop();
            var elapsedMs = watch.ElapsedMilliseconds;

            if (elapsedMs < MINIMUM_DISPLAY_TIME) //ensure progress bar is displayed for at least 100 milliseconds, otherwise it just looks like the parent main form glitches.
            {
                long lDelay = MINIMUM_DISPLAY_TIME - elapsedMs;

                Thread.Sleep((int)lDelay);
            }
        }
    }
}

The form design looks like this : -

[![enter image description here][1]][1]


  [1]: https://i.stack.imgur.com/n4XqU.jpg


And I call it like this: -

            using (Yournamespace.frmProgressBar frm = new Yournamespace.frmProgressBar(Yourprocess))
            {
                frm.ShowDialog(this);
            }


Yourprocess is the code that you want to execute that is causing the delay.

The main problem with this implementation is Yourprocess cannot return a value or take parameters. I am sure the code can be changed to accomodate this but I did not have time so I use globals to pass in data and to see results(shame on me).

This is not my code, although I have modified it, came from a you tube video - Wait Form Dialog.

Edit. I forgot to say that I set my form to 100% opacity so the progress bar seems to float above my winform whenever I use it.




回答3:


There are definitely resources to help you figure this out, however I spent like 2 days figuring it out so I'm going to help you out here and save you the headache. The progress bar itself is under the main UI thread (like any objects in your form) and needs to be handled by the main thread. Whatever you are trying to do on the side can be handled by a thread like this

    String a, b;
    a = txtUsername.Text;
    b = txtPassword.Password;
    Thread Login = new Thread(() => CompleteLogin(a, b));
    InversePbVisibility();
    Login.Start();

The InversePbVisibility() method would be replaced by whatever you are doing to make the progress bar visible to the user. A quick side note, any methods that are run on your declared thread can only pass variables and not anything already under the control of the main thread.



来源:https://stackoverflow.com/questions/57377016/how-to-load-the-progressbar-at-the-same-time-my-method-is-running

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!