• (2 Pages)
  • +
  • 1
  • 2

Using the BackgroundWorker in C# Make your UI more responsive through multithreading

#16 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,839
  • Joined: 02-June 10

Posted 06 June 2010 - 11:57 AM

UPDATE:
Solved my own problem. But it is worth being aware of. If your worker thread works the console heavy like this example, that's where it gets hung up. If I quit reporting progress to the console, and instead add a GUI progresscontrol then there are no problems, hang ups, or "not responding" issues.

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int bob = 0; bob < 100000; bob++)
            {
                backgroundWorker1.ReportProgress(bob/1000);
                Application.DoEvents();
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Console.WriteLine(e.ProgressPercentage.ToString() + " %");// This will cause 'not responding'
            progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Console.WriteLine("Thread Complete");
            progressBar1.Value = 0;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();

        }
    }

Was This Post Helpful? 1
  • +
  • -

#17 Renagado  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 117
  • View blog
  • Posts: 388
  • Joined: 14-June 09

Posted 06 June 2010 - 03:34 PM

View PosttlhIn, on 06 June 2010 - 06:57 PM, said:

UPDATE:
Solved my own problem. But it is worth being aware of. If your worker thread works the console heavy like this example, that's where it gets hung up. If I quit reporting progress to the console, and instead add a GUI progresscontrol then there are no problems, hang ups, or "not responding" issues.


Yes, writing to console from a forms application isn't as easy as it should be(sadly enough). It won't work this way even if you just add a Console.WriteLine("hello"); to a button's click event.

However it's easy enough to add a bg-worker to a console project, you just need to manually set up the event handlers. This is the general idea, in case somebody is wondering:

using System;
using System.ComponentModel;

namespace ConsoleApplication1
{
    class Program
    {
        static BackgroundWorker bg = new BackgroundWorker();
        static void Main(string[] args)
        {
            
            bg.DoWork +=new DoWorkEventHandler(bg_DoWork);
            bg.ProgressChanged +=new ProgressChangedEventHandler(bg_ProgressChanged);
            bg.WorkerReportsProgress = true;
            bg.RunWorkerAsync();
            
            Console.ReadKey();
            
        }
        static void bg_DoWork(object sender, EventArgs e)
        {
            for (int bob = 0; bob < 100000; bob++)
            {
                bg.ReportProgress(bob / 100);
            }
        }
        static void bg_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Console.WriteLine(e.ProgressPercentage);
        }
       
    }
}



Was This Post Helpful? 1
  • +
  • -

#18 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,839
  • Joined: 02-June 10

Posted 06 June 2010 - 03:44 PM

Exactly. Anything talking to the outside world has to take place from the ProgressChanged event handler.
I found that Console writting from within the main DoWork and raising custom events from inside the DoWork would causing hanging.
Live and learn.

For example

static void bg_DoWork(object sender, EventArgs e)
        {
RaiseCustomStartedEvent();
            for (int bob = 0; bob < 100000; bob++)
            {
                bg.ReportProgress(bob / 100);
            }
RaiseCustomFinishedEvent();
        }


Was a problem, even though raising events really shouldn't be.

So I had to adjust some methods to respond to

static void bg_DoWork(object sender, EventArgs e)
        {
bg.ReportProgress(0);// At zero we must be starting.
            for (int bob = 0; bob < 100000; bob++)
            {
                bg.ReportProgress(bob / 100);
            }
bg.ReportProgress(100);// At 100 we must be done.
        }


Was This Post Helpful? 0
  • +
  • -

#19 Guest_zubair*


Reputation:

Posted 14 June 2010 - 03:35 AM

can i stop the work of background worker thread,when main thread is executing the code of progressChangeEvent code..and when main thread complete its execution then again backGround thread start working.
Was This Post Helpful? 0

#20 tlhIn`toq  Icon User is offline

  • Please show what you have already tried when asking a question.
  • member icon

Reputation: 5529
  • View blog
  • Posts: 11,839
  • Joined: 02-June 10

Posted 14 June 2010 - 04:04 AM

View Postzubair, on 14 June 2010 - 02:35 AM, said:

can i stop the work of background worker thread,when main thread is executing the code of progressChangeEvent code..and when main thread complete its execution then again backGround thread start working.


Yes you can. The MSDN page for Backgroundworker shows it quite well.
http://msdn.microsof...oundworker.aspx

Have you already tried coding something up? Do you have a specific problem with your cancel not working?
Was This Post Helpful? 0
  • +
  • -

#21 Guest_fayer*


Reputation:

Posted 09 December 2010 - 02:14 AM

Great tutorial, very clearly explained. Thanks
Was This Post Helpful? 0

#22 Guest_dpminusa*


Reputation:

Posted 12 December 2010 - 03:02 PM

Your tutorial was very helpful. I have a couple of suggestions and have a copy of the code I ended up with. It may be useful to others. Thanks again.

1. I needed to add:


using System.Threading;

        public static List<int> data = new List<int>();         //our return data
        public static List<int> data_new = new List<int>();     //our return data




2. I found that adding a text box to see the contents of the lists was helpful.
3. A smaller point, but ... spacing the comments out to the right and lining them up or putting them over the code is a bit easier to follow.

4. The code I used to run the tutorial was:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public static List<int> data = new List<int>();         //our return data
        public static List<int> data_new = new List<int>();     //our return data

        public Form1()
        {
            InitializeComponent();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            int time = (int)e.Argument;
            List<int> temp = new List<int>();                   //our return data
            for (int i = 0; i <= 10; i++)
            {
                if (backgroundWorker1.CancellationPending)      //checks for cancel request
                {
                    e.Cancel = true;
                    break;
                }
                backgroundWorker1.ReportProgress(i * 10, i);    //reports ProgressPercentage AND Userstate
                Thread.Sleep(time);                             //used to simulate lengthy operations, 
                temp.Add(i);                                    //in this case 10*300ms=3s(add using System.Threading)
            }
            e.Result = temp;//return temp 
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)                                    //it doesn't matter if the BG worker ends normally, or gets cancelled,
            {
			    //both cases RunWorkerCompleted is invoked, so we need to check what has happened
                foreach (var item in data_new)
                {
                    textBox1.Text += item + "\r\n";
                }
                
                MessageBox.Show("You've cancelled the backgroundworker!.");
            }
            else
            {
                data.AddRange((List<int>)e.Result);             //copies return value to public list we declared before

                foreach (var item in data)
                {
                    textBox1.Text += item + "\r\n";
                }

                MessageBox.Show("Done");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
            data.Clear();
            data_new.Clear();
            backgroundWorker1.RunWorkerAsync(300);              //300 gives a total of 3 seconds pause
        }

        private void button2_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();                    //makes the backgroundworker stop
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            lblProgress.Text = e.ProgressPercentage.ToString() + "%";
            data_new.Add((int)e.UserState);                     //casts the userstate into integer and adds it to a List
        }
    }
}




Was This Post Helpful? 0

#23 Guest_Tripati Patro*


Reputation:

Posted 14 February 2011 - 11:25 PM

Nice Article. Helpful code.
Was This Post Helpful? 0

#24 ThangDo  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 06-October 11

Posted 01 December 2012 - 08:27 AM

This is extremely helpful and in detail.
Thank you so much for posting this tutorial.
Was This Post Helpful? 0
  • +
  • -

#25 Rajo.mca  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 16-December 12

Posted 16 December 2012 - 07:40 AM

View Postdpminusa, on 12 December 2010 - 03:02 PM, said:

Your tutorial was very helpful. I have a couple of suggestions and have a copy of the code I ended up with. It may be useful to others. Thanks again.

1. I needed to add:


using System.Threading;

        public static List<int> data = new List<int>();         //our return data
        public static List<int> data_new = new List<int>();     //our return data




2. I found that adding a text box to see the contents of the lists was helpful.
3. A smaller point, but ... spacing the comments out to the right and lining them up or putting them over the code is a bit easier to follow.

4. The code I used to run the tutorial was:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public static List<int> data = new List<int>();         //our return data
        public static List<int> data_new = new List<int>();     //our return data

        public Form1()
        {
            InitializeComponent();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            int time = (int)e.Argument;
            List<int> temp = new List<int>();                   //our return data
            for (int i = 0; i <= 10; i++)
            {
                if (backgroundWorker1.CancellationPending)      //checks for cancel request
                {
                    e.Cancel = true;
                    break;
                }
                backgroundWorker1.ReportProgress(i * 10, i);    //reports ProgressPercentage AND Userstate
                Thread.Sleep(time);                             //used to simulate lengthy operations, 
                temp.Add(i);                                    //in this case 10*300ms=3s(add using System.Threading)
            }
            e.Result = temp;//return temp 
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)                                    //it doesn't matter if the BG worker ends normally, or gets cancelled,
            {
			    //both cases RunWorkerCompleted is invoked, so we need to check what has happened
                foreach (var item in data_new)
                {
                    textBox1.Text += item + "\r\n";
                }
                
                MessageBox.Show("You've cancelled the backgroundworker!.");
            }
            else
            {
                data.AddRange((List<int>)e.Result);             //copies return value to public list we declared before

                foreach (var item in data)
                {
                    textBox1.Text += item + "\r\n";
                }

                MessageBox.Show("Done");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
            data.Clear();
            data_new.Clear();
            backgroundWorker1.RunWorkerAsync(300);              //300 gives a total of 3 seconds pause
        }

        private void button2_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();                    //makes the backgroundworker stop
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            lblProgress.Text = e.ProgressPercentage.ToString() + "%";
            data_new.Add((int)e.UserState);                     //casts the userstate into integer and adds it to a List
        }
    }
}





For variable , public static List<int> data_new = new List<int>(); how can assign values . please suggest and i tried but giving error....
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2