0

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");
}
Katrell
  • 1
  • 4
  • `I am having difficulty figuring out how to since my progress bar with my method` you didn't finish your sentence. Also, what do you mean by `load progressbar`? – slow Aug 06 '19 at 13:36
  • Possible duplicate of [Thread not updating progress bar control - C#](https://stackoverflow.com/questions/16347008/thread-not-updating-progress-bar-control-c-sharp) – CoastN Aug 06 '19 at 13:38
  • @sLw I have updated my question and my goal is to have my progress bar sync with the time it is taking for my method to run. – Katrell Aug 06 '19 at 14:09
  • Ah, now I get what you're trying to do. I thought you wanted to sync this method(the Button_click method) with the progressbar, but you want to sync it with `only` the method `excelHelper.InsertNewRows();` Did I understand this correctly? If so, then you would have to sync it inside the Method `InsertNewRows()` otherwise you don't know at which stage it is – slow Aug 06 '19 at 14:30
  • Also, your `excelHelper.InsertNewRows();` is running on the current thread, so i guess it would block the thread until it's done. If it doesn't block the thread, then it is doing it faster then you can see, but then again, you couldn't even see the progressbar... – slow Aug 06 '19 at 14:32
  • Try to narrow down to where your problem **exactly** is. – slow Aug 06 '19 at 14:33
  • @sLw I believe you have it . What I want it to do: When I click on the submit button I want it to fire both my ProgressBar and method at the same time , the progressBar should Monitor the length of time it takes my method to complete from 0% to 100% . What it is doing: When I click on the ButtonSubmit_Click button it hits my thread with my code for my progressBar ignores it, then it statrts my method , without loading my progressbar. – Katrell Aug 06 '19 at 14:47
  • As I said, you would have to do the **sync** inside of the `excelHelper.InsertNewRows();` method. otherwise it would be 0% and then instantly 100% – slow Aug 06 '19 at 14:49
  • @sLw can you provide a example? – Katrell Aug 06 '19 at 14:54

3 Answers3

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

Yoboi
  • 19
  • 9
  • I am not sure this approach will work because my function tends to loop depending on how many fields/styles is entered. I assume this would result in the progress bar looping back to 10 when a new style/Field is entered. – Katrell Aug 06 '19 at 14:27
0
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.

ZedLepplin
  • 307
  • 2
  • 12
0

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.