C# Background Worker general help

Hello all and thanks ahead for any help. I am trying to get my mind around how the BackgroundWorker works. I have tried various itteration of code and the following example I have developed is the closest I have come to working like I want it. This example I have come up with pretends that there are 4 temperature samplings each from Mars and Earth. There are two radiobuttons and a richtextbox on the form, if the user wants to get constant updated temperatures on Earth, they click the Earth radiobutton, likewise for Mars. There are subtle differences in the way I have implemented the worker here than the way MSDN does but I have tried the MSDN way and have the same problem.  In the radioButtonEARTH and MARS methods, I check for the bgw(BackGroundWorker) is busy, if so, cancel then start a new bgw. As posted here, I have a MessageBox and Sleep thread. This way seems to work...well mostly the UI the way it responds seems a little buggy but eventually will the return the temperatures on a 5 second interval as intended. If instead of a MessageBox/Thread.Sleep I use the while(bgw.IsBusy) the application hangs as if the bgw is always busy. However, if you uncomment out the MessageBox in the RunWorkerCompleted you will see that when the bgwTEMPERATURECHECKER.CancelAsync(); is called the bgw is completed, but for some reason stays busy. I hope the code is self explainatory but I will answer any questions about what I am trying to do. I would seem that some sort of GUI call has to be made to the main thread (the MessageBox call) in order for the bgw to reset. But this is just my inexperienced observation. Any help would be appreciated!! Thanks
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
 
namespace bgwexample
{
    public partial class Form1 : Form
    {
        public List<string> temperatures = new List<string>(1);
 
        public Form1()
        {
            InitializeComponent();
            InitializeBackgroudWorker();           
        }        
        private void InitializeBackgroudWorker()
        {
            bgwTEMPERATURECHECKER.DoWork += 
                new System.ComponentModel.DoWorkEventHandler(this.bgwTEMPERATURECHECKER_DoWork);
            bgwTEMPERATURECHECKER.ProgressChanged +=
                new ProgressChangedEventHandler(bgwTEMPERATURECHECKER_ProgressChanged);
            bgwTEMPERATURECHECKER.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(bgwTEMPERATURECHECKER_RunWorkerCompleted);
        } 
        private void bgwTEMPERATURECHECKER_DoWork(
            object sender, DoWorkEventArgs e)
        {
            int i = 0;
            bool continuegettingtemperatures = true;            
 
            while (continuegettingtemperatures)
            {
                if (bgwTEMPERATURECHECKER.CancellationPending)
                {
                    e.Cancel = true;
                    continuegettingtemperatures = false;
                }
                else
                {
                    if (i == 0)
                    {
                        bgwTEMPERATURECHECKER.ReportProgress(1);
                        getTemperatures((string)e.Argument);
                        bgwTEMPERATURECHECKER.ReportProgress(100);
                        i++;
                    }
                    else if (i == 50) i = 0;
                    else i++;                    
                }                                  
                Thread.Sleep(100);
            }
        }
        private void getTemperatures(string earthORmars)
        {
            Random rand = new Random();
            if (earthORmars == "earth")
            {
                temperatures.Add(rand.Next(100).ToString() + "F");
                temperatures.Add(rand.Next(100).ToString() + "F");
                temperatures.Add(rand.Next(100).ToString() + "F");
                temperatures.Add(rand.Next(100).ToString() + "F");
            }
            else if (earthORmars == "mars")
            {
                temperatures.Add(rand.Next(100).ToString() + "C");
                temperatures.Add(rand.Next(100).ToString() + "C");
                temperatures.Add(rand.Next(100).ToString() + "C");
                temperatures.Add(rand.Next(100).ToString() + "C");
            }
            else
            {
                temperatures.Add("0");
                temperatures.Add("0");
                temperatures.Add("0");
                temperatures.Add("0");
            }
        }
        private void bgwTEMPERATURECHECKER_ProgressChanged(
            object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == 1)
            {
                temperatures.Clear();
                richTextBoxTEMPERATURES.Clear();
            }
            else if (e.ProgressPercentage == 100)
            {
                foreach (string x in temperatures)
                    richTextBoxTEMPERATURES.AppendText(x + "\n");
            }
            else
            {
            }
        }
        private void bgwTEMPERATURECHECKER_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
            //MessageBox.Show("bgwTEMPERATURECHECKER_RunWorkerCompleted");
        } 
        private void radioButtonEARTH_Click(object sender, EventArgs e)
        {
            radioButtonEARTH.Checked = true;
            radioButtonMARS.Checked = false;
            
            if (bgwTEMPERATURECHECKER.IsBusy)
            {
                bgwTEMPERATURECHECKER.CancelAsync();
                MessageBox.Show("Switching to Earth temperatures");
                Thread.Sleep(1000);
                //while (bgwTEMPERATURECHECKER.IsBusy) Thread.Sleep(1000);
            }
            bgwTEMPERATURECHECKER.RunWorkerAsync("earth");
        }
        private void radioButtonMARS_Click(object sender, EventArgs e)
        {
            radioButtonEARTH.Checked = false;
            radioButtonMARS.Checked = true;
            
            if (bgwTEMPERATURECHECKER.IsBusy)
            {
                bgwTEMPERATURECHECKER.CancelAsync();
                MessageBox.Show("Switching to Mars temperatures");
                Thread.Sleep(1000);
                //while (bgwTEMPERATURECHECKER.IsBusy) Thread.Sleep(1000);
            }
            bgwTEMPERATURECHECKER.RunWorkerAsync("mars");
        }
 
 
    }//end public partial class Form1 : Form
}//end namespace bgwexample

Open in new window

bgwexample.txt
jerryleeclarkAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

p_davisCommented:
it may not be the best way but i was having trouble with the isbusy flag as well. i put in an Application.DoEvents(); and it registers as it should.

maybe try:
private void radioButtonEARTH_Click(object sender, EventArgs e)
        {
            radioButtonEARTH.Checked = true;
            radioButtonMARS.Checked = false;
            
            Application.DoEvents(); //<-- modified code
 
            if (bgwTEMPERATURECHECKER.IsBusy)
            {
                bgwTEMPERATURECHECKER.CancelAsync();
                MessageBox.Show("Switching to Earth temperatures");
                //Thread.Sleep(1000); <--modified code
                //while (bgwTEMPERATURECHECKER.IsBusy) Thread.Sleep(1000);
            }
            bgwTEMPERATURECHECKER.RunWorkerAsync("earth");
        }

Open in new window

0
mastooCommented:
Let's say thread #1 is the gui thread and #2 is the bgw.  The guts of a gui is something called a message pump and it is what keeps a gui responsive.   When a gui thread loops in some processing, it never lets the pump run and that is what makes the gui unresponsive.  DoEvents, MessageBox.Show, etc., let the message pump run.

Anyway, when thread #2 calls ReportProgress, what it is really doing is queueing up a call for the message pump to handle.  It is done this way so the handler for ReportProgress, bgwTEMPERATURECHECKER_ProgressChanged, will run in the context of thread #1.

So, if you put thread #1 into a tight loop checking IsBusy it will never let the message pump respond to the ReportProgress.  But calling DoEvents or MessageBox.Show, and the pump runs and it can process the call.

On a side note, does the MSDN sample really manipulate the temperature list like this?  I would think clearing the list on thread #1 would at times conflict with #2's use of the list since the list instance is not thread safe.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jerryleeclarkAuthor Commented:
mastoo,
Hum,  I thought that the basic idea here was to have the second thread update the graphical elements (textboxes labels etc) as it sees fit and that can be accomplished in either the  "_DoWork", "_RunWorkerCompleted" OR  the  "_ProgressChanged" methods and that would be thread safe. It would seem at the very least changing those elements in the  "_ProgressChanged"  method should be safe. I clear the box in the  "_ProgressChanged" method so I am confused at how you think it is not thread safe.
On my reference to the MSDN site, what I mean is for example in the DoWork method one of the first things they do is declare a
BackgroundWorker worker = sender as BackgroudWorker;
and any progress changes or calls to the bgw thread seems to happen via the "worker" instead of the global bgwTEMPERATURECHECKER. When working within one self, maybe using "worker" makes sense, but like I said, setting up this example my way or MSDN way has the same trouble.

I understand now your explaination and I think I have figured out how to solve my problem but I ended up solving it with two richtextboxes on top of each other. Instead of the radiobuttons being the pusher of the thread, I decided to create two threads, one for earth and one for mars. they just sit happily in the background doing what they do and if the user clicks the earth or mars radiobuttons then all the code there does is show or hide the richtextbox. The two richtextboxes being richtextboxEARTH and richtextboxMARS  of course. They are positioned exactly on top of each other so clicking the radio buttons just show and bringtofront the one of interest and hide the other. Although this seems like cheeting in a strange way it makes more since. The real idea is that you want the program to always be aware of the temperatures in both places and the radiobuttons should not be the genesis for that, just that they change the view so you can see what the bgw has done.
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

mastooCommented:
Thanks, hope that helped.  My comment about not being thread-safe referred to the member variable:

public List<string> temperatures

It was being updated from both threads, possibly simultaneously.  One thread is adding while the other clears it.
0
jerryleeclarkAuthor Commented:
YES, I figured that one out while changing to two different bgw's. Thank you I thought you were refering to the richtextbox, somewhere along the way dealing with two threads, it made sense to have two list, two richtextboxes etc. I am currious though, is it really a cheet to have to UI objects on top of each other?
0
mastooCommented:
Nope.  It might not be as "elegant" as some solutions but it's all about ease of understanding the code, so if it passes that test you're good.
0
jerryleeclarkAuthor Commented:
Thanks so much for all your help, pressing on to Encrypted registry keys....dang!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.