John red
John red

Reputation: 31

C# Accessing element from other thread

How can I do to access an element from another thread? In the case, I have a richtextbox in the Main Thread (GUI), and I'm running a method on a secondary thread. I want to access the richeditbox through the secondary thread

private void Log(string input, Label lbl)
{
  lbl.Invoke(new Action(()=>
    {
      lbl.Text = "Status: " + input;
      Thread.Sleep(50);
    }));
}

void Run()
{
   foreach (string line in richTextBox1.Lines)
    {
      Log(line, label1);
      Thread.Sleep(500);
    }
}

private void button1_Click(object sender, EventArgs e)
{
  ThreadStart th = new ThreadStart(() => Run());
  Thread th2 = new Thread(th);
  th2.Start();
  //th2.Join();
}

The following error is shown:

Invalid thread operation: control 'richTextBox1' accessed from a thread that is not the one in which it was created.

Upvotes: 1

Views: 387

Answers (2)

Idle_Mind
Idle_Mind

Reputation: 39122

Here's another version...not that you shouldn't be sleeping in the Log() method as that is running in the UI thread!

private void button1_Click(object sender, EventArgs e)
{
    ThreadStart th = new ThreadStart(() => Run());
    Thread th2 = new Thread(th);
    th2.Start();
}

void Run()
{
    string[] lines = (string[])richTextBox1.Invoke(new Func<string[]>(() => richTextBox1.Lines));
    foreach (string line in lines)
    {
        Log(line, label1);
        Thread.Sleep(500);
    }
}

private void Log(string input, Label lbl)
{
    lbl.Invoke(new Action(() =>
    {
        lbl.Text = "Status: " + input;
    }));
}

Upvotes: 0

Michael Gunter
Michael Gunter

Reputation: 12811

You're already doing this. Your Log method shows the correct thing to do -- use Invoke to run some code on the UI thread. In this case, you could do something like:

void Run()
{
    var getLines = new Func<object>(() => richTextBox1.Lines);
    var lines = (string[]) richTextBox1.Invoke(getLines);
    foreach (var line in lines)
    {
        Log(line, label1);
        Thread.Sleep(500);
    }
}

However, this really isn't necessary. It looks like you really want to read the Lines property once when your button is clicked and just pass it to the background thread.

void Run(string[] lines)
{
    foreach (var line in lines)
    {
        Log(line, label1);
        Thread.Sleep(500);
    }
}

private void button1_Click(object sender, EventArgs e)
{
    var lines = richTextBox1.Lines;
    var th = new ThreadStart(() => Run(lines));
    var th2 = new Thread(th);
    th2.Start();
}

Upvotes: 1

Related Questions