Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

C# Threading

Options
  • 07-03-2006 5:58pm
    #1
    Closed Accounts Posts: 214 ✭✭


    I' m creating a perl ide, in vs 2003 i have a thread running which takes in data from perl compiler in and outputs it to a text box,

    i converted the project to 2005 but i get the problem

    "Cross-thread operation not valid: Control 'txtOutput' accessed from a thread other than the thread it was created on."

    I understand that i'm accessing the text box on a different thread but i don't know how to go about fixing it

    the code for the compiler class is

    using System;
    using System.IO;
    using System.Threading;
    using System.Diagnostics;

    namespace Interpreter
    {
    /// <summary>
    /// Summary description for compiler.
    /// </summary>
    public class compiler
    {
    public System.Windows.Forms.RichTextBox tb1 = null;
    StreamReader sr;
    Process proc;
    public Thread th;

    public compiler(StreamReader sr,Process proc)
    {
    this.sr = sr;
    this.proc = proc;

    Thread th = new Thread(new ThreadStart(this.StreamThread));
    th.Start();
    }

    //this thread is used to read back it the output from the
    //compiler while the process is running
    public void StreamThread()
    {
    while(sr.Peek() != -1)
    {
    {
    //This outputs to text box
    this.tb1.AppendText(sr.ReadLine() + "\n");
    }
    }
    }
    }
    }


Comments

  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


    Oh I remember this one....attended an entire lecture on how to avoid this problem elegantly while at TechEd in 2004.

    I'll see if I can dig up the code for you when I'm back in the office tomorrow.

    Basically, though, you can only safely write to UI objects from the main thread, so you need to be able to call back to a "handler" in the main thread which will subsequently do the writing for you, rather than calling to the object directly as you've done.

    jc


  • Closed Accounts Posts: 4,943 ✭✭✭Mutant_Fruit


    You need to use "Delegates" to do what you want. Try something like this (you're MUCH better reading up on this to understand it fully).

    When you want to set text to a textbox, you should call the SetText method passing it the textbox you want to set the text too, and the text you want to use.
    // This is an example delegate you could use to generically set text safely to a textbox.
            private delegate void SetTextToTextBox(TextBox target, string text);
    
            private void SetText(TextBox mytextbox, string mytext)
            {
                if (mytextbox.InvokeRequired)
                {
                    // we need to use our delegate as we aren't on the mainthread
                    SetTextToTextBox d = new SetTextToTextBox(SetText);
                    d.Invoke(mytextbox, mytext);
                }
                else
                {
                    // we are on main thread (or we're using a delegate) so set text safely
                    mytextbox.Text = mytext;
                }
            }
    
    

    EDIT: Also, rather than appending one letter at a time (pretty wasteful CPU wise) use a stringbuilder, and append the letters to your string builder, and everytime 10-15 letters are appended to the stringbuilder, send it to your textbox. Or just send it to the textbox once you've read all your data. That'd be by far the most efficient.


  • Closed Accounts Posts: 214 ✭✭rancheros


    thanks for the help i got it working

    new code is

    using System;
    using System.IO;
    using System.Threading;
    using System.Diagnostics;

    namespace Interpreter
    {
    /// <summary>
    /// Summary description for compiler.
    /// </summary>
    public class compiler
    {
    public System.Windows.Forms.RichTextBox tb1 = null;
    StreamReader sr;
    Process proc;
    public Thread th;


    public delegate void myDelegat();
    public compiler(StreamReader sr,Process proc)
    {
    this.sr = sr;
    this.proc = proc;
    Thread th = new Thread(new ThreadStart(this.StreamThread));
    th.Start();
    }

    //this thread is used to read back it the output from the
    //compiler while the process is running

    public void InternalSafeAppend()
    {
    this.tb1.AppendText(sr.ReadLine() + "\n");
    }

    public void StreamThread()
    {
    while(sr.Peek() != -1)
    {
    if (tb1.InvokeRequired)
    {
    Object[] parameters = {};
    tb1.Invoke(new myDelegat(InternalSafeAppend), parameters);
    }

    }
    }
    }
    }


Advertisement