-3

I've created a simple app that adds 10 times a string to a ListView every second and displays it. All this is done using a BackgroundWorker and a ProgressBar that shows the adding progress. My question is, since I've heard that pausing a thread is very dangerous and can lead to several problems, how can I replace the Thread.Sleep with let's say a DispatcherTimer? What if I would add 1000000 elements to this list and report the progress? Is it better to use Thread.Sleep(1) or something else in this case?

My code is the following:

    private BackgroundWorker worker = new BackgroundWorker();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnAggiungi_Click(object sender, RoutedEventArgs e)
    {
        worker.WorkerReportsProgress = true;
        worker.DoWork += worker_DoWork;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        String text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
        int min;
        int max = 10;

        for (min = 1; min <= max; min++)
        {
            int progressPercentage = Convert.ToInt32((double)min / max * 100);
            worker.ReportProgress(progressPercentage, text);
            Thread.Sleep(100);
        }
    }

    private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        pb.Value = e.ProgressPercentage;
        lstLoremIpsum.Items.Add(e.UserState.ToString());
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        lblCompleted.Content = "Done";
    }

Screenshot:

user2729661
  • 9
  • 1
  • 1
  • 6
  • Calling Thread.Sleep() on a worker thread is not "dangerous". Pretty hard to see the usefulness of code like this btw. – Hans Passant May 03 '15 at 16:50
  • @HansPassant what do you mean by usefulness? it's just an example. – user2729661 May 03 '15 at 16:53
  • Use a [timer](https://msdn.microsoft.com/en-us/library/System.Timers.Timer(v=vs.110).aspx), set the interval to an appropriate value and update the progressbar? – Odrai May 03 '15 at 16:54
  • @Odrai a DispatcherTimer actually, since I'm dealing with WPF. Yes, of course, but the problem is I don't know where to start from. – user2729661 May 03 '15 at 16:55
  • You can use the same code as the [example](https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer%28v=vs.110%29.aspx). In the dispatcherTimer_Tick you can add your worker_DoWork code and remove the Thread.Sleep (set the sleep value (100) as the Interval of the timer). – Odrai May 03 '15 at 16:59
  • Maybe I don't understand your question :) Why are you using a Thread.Sleep? – Odrai May 03 '15 at 17:04
  • @Odrai because otherwise the ProgressBar isn't being updated. – user2729661 May 03 '15 at 17:06
  • 1
    How do you know it isn't being updated? I copy-paste your code in my project and everything works fine. If you set your int max to 10000, do you see an updated progressbar after a while? (10 is a really small value and your computer handles it so fast, that you think the PB is never updated). – Odrai May 03 '15 at 17:12
  • @Odrai try with 1 milion elements and see that it freezes :) I mean the progressbar is updated very quickly that I can't see the progress. 1 milion takes about 22 seconds on my machine. – user2729661 May 03 '15 at 17:18
  • If your work is truly periodic, then you can _replace_ your use of `BackgroundWorker` with `DispatcherTimer`. There are dozens, if not hundreds, of existing questions on Stack Overflow discussing the use of timers. Unfortunately, it's not really clear what you are trying to do here or what your actual question is. – Peter Duniho May 03 '15 at 17:28

1 Answers1

-1

After some testing:

worker.ReportProgress is meant to report the overall progress of the BackgroundWorker back to the UI thread. This way you can display the progress and inform your users. However, you're using it to actually add strings to an listbox/ listview. You're better off compiling adding the strings (text) in memory (buffer in a list/ array) and then populating listbox/ listview once when the background worker completes. If your GUI still freezes, add the strings per 50, 100 or 200.

And another minor improvement:

private void UpdateProgressbar(int percentage)
{
    if (InvokeRequired)
    {
        this.BeginInvoke(new Action<int>(UpdateProgressbar), new object[] { percentage });
        return;
    }

    pb.Value = percentage;
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    UpdateProgressbar(e.ProgressPercentage);           
}
Odrai
  • 2,163
  • 2
  • 31
  • 62