private void cmdSales_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
            timer2.Start();
        }
        private void timer2_Tick(object sender, EventArgs e)
        {

            TimeSpan ts = DateTime.Now.Subtract(startDate);

            string sTime ="  ..." + ts.Minutes.ToString("00") +

               ":" + ts.Seconds.ToString("00") +

               ":" + ts.Milliseconds.ToString("000");

            toolStripStatusLabelTime.Text = sTime;

            if (toolStripProgressBar1.Value ==

                toolStripProgressBar1.Maximum)

            {

                toolStripProgressBar1.Value = 0;

            }

            toolStripProgressBar1.PerformStep();

        
        }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            toolStripStatusLabel1.Text = "Loading ... " +

                 "Thanks for your patience";

            frmSales objfrmSChild = frmSales.GetChildInstance();
[B]            objfrmSChild.MdiParent = this;
[/B]            objfrmSChild.Show();
            objfrmSChild.BringToFront();

        }
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            toolStripProgressBar1.Value = 100;


            toolStripStatusLabel1.Text = "";

            toolStripProgressBar1.Value = 0;

            timer2.Stop();

            toolStripStatusLabelTime.Text = "";
        }

Progress bar is on the MDI parent form and i would like the progress bar to run after clicking on the button and when the child is loaded the progress bar will stop.

somehow i face problem when comes to "objfrmSChild.MdiParent = this;". Error msg : "Cross-thread operation not valid: Control 'frmContainer' accessed from a thread other than the thread it was created on."

How can i prevent this from happening ?

Dani AI

Generated

The exception happens because WinForms controls are tied to the thread that created them (the UI thread). Any attempt to set MdiParent, call Show(), or touch ToolStrip controls from BackgroundWorker.DoWork (a thread-pool thread) triggers the “Cross-thread operation not valid” error.

A simple, robust pattern:

  • Do all heavy/non-UI work inside DoWork and put the result into e.Result.
  • Use ReportProgress (WorkerReportsProgress = true) for incremental UI updates, or update the progress UI from a timer as already used.
  • Create and show the MDI child on the UI thread — for example in RunWorkerCompleted (it runs on the UI thread), so MdiParent = this and Show() are safe there.

Example (illustrative, not identical to existing snippets):

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var data = LoadHeavyData(); // no control access
    e.Result = data;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    StopProgressTimer();
    var child = new frmSales((MyData)e.Result);
    child.MdiParent = this;   // safe here — UI thread
    child.Show();
}

If immediate UI work from DoWork is unavoidable, marshal it back to the UI thread with BeginInvoke/Invoke:

this.BeginInvoke((Action)(() =>
{
    var child = new frmSales();
    child.MdiParent = this;
    child.Show();
}));

Notes and cautions: passing the main form into RunWorkerAsync (as suggested by ) does not remove the cross-thread restriction — DoWork still runs off the UI thread. ’s BeginInvoke approach is valid for marshaling, but RunWorkerCompleted or ProgressChanged are cleaner for typical cases. Avoid suppressing the check (CheckForIllegalCrossThreadCalls = false) or creating controls on a background thread without a separate message loop — both cause subtle bugs.

Recommended Answers

All 6 Replies

if you pass the instance of the main form to the background worker then cast it to a form, you can then easily pass that instance to the new form. Simple stuffs, Background workers take an object as a argument in the doworkeventargs, just pass it in, then pull it back out.

no need for anything complicated here.

is there a pre-visual ??

when you call the runworker method pass to it the instance you need

backgroundWorker1.RunWorkerAsync(this);

then in the dowork event handler extract that instance to a variable casting it to the type that it is, an instance of a form.

Form formInstance = (Form)e.Argument;

Thin just pass that instance on to your new form

objfrmSChild.MdiParent = formInstance;

easy as pie :)

happy coding

Diamonddrake,

Im newbie in C#, do u can explain again(detailed) or have an example.

PS: My english is very poor...

Im not sure how much clearer i could be, so I am just going to repost your code, with the modifications that fixes the issue.

private void cmdSales_Click(object sender, EventArgs e)
        {
           [B] backgroundWorker1.RunWorkerAsync(this);[/B]
            timer2.Start();
        }
        private void timer2_Tick(object sender, EventArgs e)
        {

            TimeSpan ts = DateTime.Now.Subtract(startDate);

            string sTime ="  ..." + ts.Minutes.ToString("00") +

               ":" + ts.Seconds.ToString("00") +

               ":" + ts.Milliseconds.ToString("000");

            toolStripStatusLabelTime.Text = sTime;

            if (toolStripProgressBar1.Value ==

                toolStripProgressBar1.Maximum)

            {

                toolStripProgressBar1.Value = 0;

            }

            toolStripProgressBar1.PerformStep();

        
        }
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {

     //get instance of main form from eventargs
     [B]Form formInstance = (Form)e.Argument;[/B]
            
toolStripStatusLabel1.Text = "Loading ... " +

                 "Thanks for your patience";

            frmSales objfrmSChild = frmSales.GetChildInstance();
            //set mdiparent to instance passed to dowork event
           [B]objfrmSChild.MdiParent = formInstance;[/B] 
            objfrmSChild.Show();
            objfrmSChild.BringToFront();

        }
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            toolStripProgressBar1.Value = 100;


            toolStripStatusLabel1.Text = "";

            toolStripProgressBar1.Value = 0;

            timer2.Stop();

            toolStripStatusLabelTime.Text = "";
        }

Happy Coding

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.