0

1st off I am not even sure what a C# Cross-Thread Operation is, so seeing this debug message blows my mind from the start - Cross-thread operation not valid: Control 'panel1' accessed from a thread other than the thread it was created on. I am just attempting to write to a textbox to show the progress of my procedures. Thread.Sleep() is used in the code below for brevity. I receive the debug message when my code hits the line panel1.Controls.Add(txt); And here is full code:

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
    private DateTime now = DateTime.Now;
    private int i = 0;
    TextBox txt = new TextBox();

     public Form1()
    {
        InitializeComponent();
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = false;
        backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
        backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
    }

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

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
            panel1.Controls.Add(txt);
            MethodOne();
            MethodTwo();
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }

    private void MethodOne()
    {
        txt.Text = "MethodOne Process Has Begun....." + now;
        Thread.Sleep(100);
        txt.Text = "MethodOne Process Has Finished....." + now;
    }
    private void MethodTwo()
    {
        txt.Text = "MethodTwo Process Has Begun....." + now;
        Thread.Sleep(100);
        txt.Text = "MethodTwo Has Finished....." + now;
    }
}
}

Please let me know if I need to provide any further details or more information about how my windows form is set-up.

Bob Goblin
  • 1,251
  • 3
  • 16
  • 33
  • I'm not sure how surprising this could be... when you've created a background thread and set it working. As Robert said - controls cannot be accessed from a thread different to what they were created on. – slugster Mar 28 '15 at 02:17

2 Answers2

2

You can't access UI controls directly from the BackgroundWorker thread. UI controls are on a separate thread, hence the error. This is not allowed:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    panel1.Controls.Add(txt);
    ...
}

The BackgroundWorker allows you to pass a number (usually representing a percentage), and another object back (it could be anything, such as your text). What I'd recommend is this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var bgw = (BackgroundWorker)sender;

    bgw.ReportProgress(33, "MethodOne Process Has Begun.....");
    MethodOne();

    bgw.ReportProgress(66, "MethodTwo Process Has Begun.....");
    MethodTwo();

    bgw.ReportProgress(100, "All Processes Finished.");
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;

    var statusMessage = e.UserState.ToString();
    // Display statusMessage in an appropriate control, i.e. a Label
}
Grant Winney
  • 65,241
  • 13
  • 115
  • 165
  • This probably works too, since `panel1.Controls.Add` is being called from an event that's marshaled on the UI thread. Note that `progressBar1.Value = e.ProgressPercentage;` already works. – Robert Harvey Mar 28 '15 at 02:17
  • Would it be better (or does it even matter) to place the panel1.Controls.Add(txt) under the button1_Click() event or the Form1() event? – Bob Goblin Mar 28 '15 at 02:23
1

Actions that take place on the UI from a different thread require a special marshaling process called an Invoke. An error occurs if you don't use the Invoke from the other thread.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • So the issue is I am attempting to modify my form via the backgroundWorker1_DoWork() procedure? – Bob Goblin Mar 28 '15 at 02:13
  • Yes. You should probably be modifying the form on the same thread; I don't see any advantage to modifying the form in a `BackgroundWorker`. `BackgroundWorker` is intended for long-running operations that don't involve the form (except for a progress indicator which is already thread-safe). See [here](https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) for a code example of Invoke. – Robert Harvey Mar 28 '15 at 02:13