LordTitiKaka
LordTitiKaka

Reputation: 2156

append to textbox from another thread

I've a Form with many tabs and I want to write to them in the same time from many threads (UI BackGroundWorker etc.) I've written this code and it is working on main tab ( the one that is visible when app starts )

    public struct Struct_Append
    {
        public RichTextBox Screen;
        public string Message;
        public Color Color;
    }

    public void AppendAllTextAllScreen (Struct_Append append  )
    {
        RichTextBox screenToPrint = append.Screen;
        Font font = new Font("Tahoma", 8, FontStyle.Regular);
        if (screenToPrint.InvokeRequired) //&& this.Visible)
        {

            append.Message = append.Message + "\n";
            try
            {
                this.Invoke(new Action<Struct_Append>(AppendAllTextAllScreen), new object[] { 
                append });
            }
            catch(Exception ex)
            {
                //handle exception
            }
             return; 
        }
        append.Message = append.Message + "\n";

        screenToPrint.SelectionFont = font;
        screenToPrint.SelectionColor = append.Color;
        screenToPrint.AppendText(append.Message);
    }

It is working from any thread , but once I set the screen to some of the other tabs , and fire it

        Struct_Append structAppend1 = new Struct_Append();
        structAppend1.Screen = scrnSta1;
        structAppend1.Color = Color.Bisque;
        structAppend1.Message = "THIS IS A TEST";
        AppendAllTextAllScreen(structAppend1);

VisualStudio2013 just get stuck and restart it self!!!!

BUT when I run it without DEBUG it runs fine

EDIT code that I used that spawn the ERROR

this is the I used to test the appendText method above

private async void DoSomthing()
{
            Task.Run(() =>
            {
                _Append structAppend1 = new _Append();
                structAppend1.Screen = ScrnSta1; ;
                structAppend1.Color = Color.Bisque;
                structAppend1.Message = "THIS IS A TEST";
                for (int i = 0; i < 5; i++)
                {
                    AppendAllTextAllScreen(structAppend1);
                }


            });
            Task.Run(() =>
            {
                _Append structAppend = new _Append();
                structAppend.Color = Color.Aquamarine;
                structAppend.Message = "THIS IS A TEST";
                structAppend.Screen = ScrnSta2;
                for (int j = 0; j < 5; j++)
                {
                    AppendAllTextAllScreen(structAppend);
                }
            });
}

scrnsta1/2 are two seperated tabs in my Form (main UI thread), and I call this method from there(UI thread)

what am I missing here ?

Upvotes: 2

Views: 1365

Answers (2)

Georgi-it
Georgi-it

Reputation: 3686

I would recommend to continue the tasks on the UI thread without using invoke. It is much safer and less error prone: Task continuation on UI thread

Task UITask= task.ContinueWith(() =>
{
 this.TextBlock1.Text = "Complete"; 
}, TaskScheduler.FromCurrentSynchronizationContext());

Upvotes: 1

Codor
Codor

Reputation: 17605

To my understanding, access to Windows Forms controls from a different thread must be done by means of the Invoke method of Control, which needs the definition of suitable delegates. In your example, these delegates would be basically the lambda expressions used in the implementation of DoSometing.

Upvotes: 1

Related Questions