Question BackgroundWorker. Multithreading. How do I run multiple forms?

csharBeginer

New member
Joined
Sep 1, 2018
Messages
3
Programming Experience
Beginner
There is
- the main form is "Main.cs".
- form with "progressBar" - "progressBar.cs" Scenario:
User. The form is "Main.cs". Presses the "Start" button three times.
Program. Opens three forms of "progressBar.cs"

How to make the data from the progress percentage "progressBar" get in real time in the corresponding "lblStatus_1", "lblStatus_3", "lblStatus_3" form "" Main.cs "?
I tried to do it, but until the end I can not figure it out.

"Main.cs".

C#:
namespace BackgroundWorkerSample
{
    public partial class Main : Form
    {
        int numOfDisc; // Number of discoveries


        public Main()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            progressBar prgrBar = new progressBar();
            prgrBar.Show();


            numOfDisc++;


            switch (numOfDisc)
            {
                case 1:
                    prgrBar.m_oWorker.RunWorkerAsync();
                    lblStatus_1.Text = "Processing......" + prgrBar.prgrBar1Val.ToString() + "%";
                    break;


                case 2:
                    prgrBar.m_oWorker.RunWorkerAsync();
                    lblStatus_2.Text = "Processing......" + prgrBar.prgrBar1Val.ToString() + "%";
                    break;


                case 3:
                    prgrBar.m_oWorker.RunWorkerAsync();
                    lblStatus_3.Text = "Processing......" + prgrBar.prgrBar1Val.ToString() + "%";
                    break;
            }




        }
    }
}

progressBar.cs
C#:
namespace BackgroundWorkerSample
{
    public partial class progressBar : Form
    {
        /// <summary>
        /// The backgroundworker object on which the time consuming operation shall be executed
        /// </summary>
        public BackgroundWorker m_oWorker;
        public int prgrBar1Val;


        public progressBar()
        {
            InitializeComponent();
            m_oWorker = new BackgroundWorker();


            m_oWorker.DoWork += new DoWorkEventHandler(m_oWorker_DoWork);
            m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
            m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);


            m_oWorker.WorkerReportsProgress = true;
            m_oWorker.WorkerSupportsCancellation = true;
        }


        /// <summary>
        /// On completed do the appropriate task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_oWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //If it was cancelled midway
            if (e.Cancelled)
            {
                lblStatus.Text = "Task Cancelled.";
            }
            else if (e.Error != null)
            {
                lblStatus.Text = "Error while performing background operation.";
            }
            else
            {
                lblStatus.Text = "Task Completed...";
            }
            btnStartAsyncOperation.Enabled = true;
            btnCancel.Enabled = false;
        }


        /// <summary>
        /// Notification is performed here to the progress bar
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_oWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Here you play with the main UI thread
            progressBar1.Value = e.ProgressPercentage;




            // *** change ***
            // progressBar1.Value    
            prgrBar1Val = progressBar1.Value;


            // *** change. End ***


            lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";


        }










        /// <summary>
        /// Time consuming operations go here </br>
        /// i.e. Database operations,Reporting
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_oWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //NOTE : Never play with the UI thread here...


            //time consuming operation
            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(100);
                m_oWorker.ReportProgress(i);


                //If cancel button was pressed while the execution is in progress
                //Change the state from cancellation ---> cancel'ed
                if (m_oWorker.CancellationPending)
                {
                    e.Cancel = true;
                    m_oWorker.ReportProgress(0);
                    return;
                }


            }


            //Report 100% completion on operation completed
            m_oWorker.ReportProgress(100);
        }


        private void btnStartAsyncOperation_Click(object sender, EventArgs e)
        {
            btnStartAsyncOperation.Enabled  = false;
            btnCancel.Enabled               = true;
            //Start the async operation here
            m_oWorker.RunWorkerAsync();
        }


        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (m_oWorker.IsBusy)
            {
                //Stop/Cancel the async operation here
                m_oWorker.CancelAsync();
            }
        }
    }
}
 

Attachments

  • 01_pr.zip
    380.9 KB · Views: 71
  • 2018-09-01_07-11-32.png
    2018-09-01_07-11-32.png
    61.8 KB · Views: 108
  • 2018-09-01_07-12-13.png
    2018-09-01_07-12-13.png
    73.2 KB · Views: 133
  • 2018-09-01_07-10-20.png
    2018-09-01_07-10-20.png
    127.3 KB · Views: 74
There's a proper way to do this. In a relationship between two forms, there is a caller and a callee. The caller is the one that creates and displays the callee. If the caller needs to pass data into the callee then it should call a method of the callee. If the caller needs to get data out of the callee then it should either call a function and get the return value, get a property or handle an event. In this case, the proper option is to handle an event. The form that is running the BackgroundWorker should handle the ProgressChanged event and then raise an event of its own, which the caller can then handle.
 
There's a proper way to do this. In a relationship between two forms, there is a caller and a callee. The caller is the one that creates and displays the callee. If the caller needs to pass data into the callee then it should call a method of the callee. If the caller needs to get data out of the callee then it should either call a function and get the return value, get a property or handle an event. In this case, the proper option is to handle an event. The form that is running the BackgroundWorker should handle the ProgressChanged event and then raise an event of its own, which the caller can then handle.

OK
I'm still studying what you described.


You could not show a bit on the example of my code as it should look?
 
If you want to learn how to raise your own events, follow the Custom Events link in my signature below. Handling the ProgressChanged event of the BackgroundWorker in the callee form is exactly the same as always. Handling the event of the callee form in the caller form is the same as always too, although you have to do it in code when you create the form rather than in the designer. I would recommend handling the FormClosed event too, so that you know when the form has closed and you can detach your event handlers.

As for the Labels, I'd suggest that you create a Dictionary<Form, Label> and store each Label against the corresponding form. When you handle an event of a form, you get a reference to the form itself from the 'sender' parameter. You can then use that to access the corresponding Label in the Dictionary and display the appropriate text.
 
Back
Top Bottom