Hi friends,
I have written following program in Csharp windows application.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Practice4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void START_Click(object sender, EventArgs e)
        {
            Thread temp_thread = new Thread(function);

            temp_thread.Start();
        }
        void function()
        {
            textBox1.Text = textBox1.Text + "Vijay";
        }
    }
}

The above program was compiled properly. But while executing i am getting following exception after clicking the START button.

Exception:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

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

Can any one please tell me how to avoid the above exception?

Regards,
Vijay Bhaskar

Recommended Answers

All 11 Replies

You can't access UI controls from another thread in the normal way. You need to use control.Invoke to access the control, this will work its way to the thread that created the control and work correctly. You can use code like this:

if (control.InvokeRequired)
    control.Invoke(SomeMethod);
else
    control.SomeNormalProperty = someValue;

...

private void SomeMethod()
{
    control.SomeNormalProperty = _someValue;
}

Invoke requires a delegate to do the actual work. You can also supply parameters to your delegate with an overload of invoke:

if (control.InvokeRequired)
    control.Invoke(SomeMethod, someValue);
else
    control.SomeNormalProperty = someValue;

...

private void SomeMethod(String someValue)
{
    control.SomeNormalProperty = someValue;
}

Hi macu,
Thanks for replying me and I understood the reason. But could you please tell me how can I change my program so that it will work (OR) Do i need to change the entire program.

Regards,
Vijay

You can't access UI controls from another thread in the normal way. You need to use control.Invoke to access the control, this will work its way to the thread that created the control and work correctly. You can use code like this:

if (control.InvokeRequired)
    control.Invoke(SomeMethod);
else
    control.SomeNormalProperty = someValue;

...

private void SomeMethod()
{
    control.SomeNormalProperty = _someValue;
}

Invoke requires a delegate to do the actual work. You can also supply parameters to your delegate with an overload of invoke:

if (control.InvokeRequired)
    control.Invoke(SomeMethod, someValue);
else
    control.SomeNormalProperty = someValue;

...

private void SomeMethod(String someValue)
{
    control.SomeNormalProperty = someValue;
}

Sure, try the following:

namespace Practice4
{
	public partial class Form1 : Form
	{
		private delegate void UpdateTextBoxHandler(String addMessage);

		public Form1()
		{
			InitializeComponent();
		}

		private void START_Click(object sender, EventArgs e)
		{
			Thread temp_thread = new Thread(function);

			temp_thread.Start();
		}

		void function()
		{
			if (textBox1.InvokeRequired)
				textBox1.Invoke(new UpdateTextBoxHandler(UpdateTextBox), "Vijay");
			else
				UpdateTextBox("Vijay");
		}

		private void UpdateTextBox(String message)
		{
			textBox1.Text += message;
		}
	}
}

I'm checking if invoking is required (i.e. because we're not in the thread that created the UI), if it is I use a delegate to set the text property. I'm using the same method to set the text property when invoke isn't required so that you have standard behaviour, e.g. if you called function() from the main thread. You could just use Invoke and not bother with the InvokeRequired property.

Hi macu,
Thanks a lot for your solution and it is working now. Now i have changed the program mentioned below.

namespace Practice4
{
public partial class Form1 : Form
{
static bool temp_flag = true;

private delegate void UpdateTextBoxHandler(String addMessage);

public Form1()
{
InitializeComponent();
}

private void START_Click(object sender, EventArgs e)
{
Thread temp_thread = new Thread(function);

while (temp_flag == true)
{
temp_thread.Start();
}
}

void function()
{
if (textBox1.InvokeRequired)
textBox1.Invoke(new UpdateTextBoxHandler(UpdateTextBox), "Vijay");
else
UpdateTextBox("Vijay");
}

private void EXIT_Click(object sender, EventArgs e)
{
temp_flag = false;
Application.Exit();
}

private void UpdateTextBox(String message)
{
textBox1.Text = textBox1.Text + " ## " + message;
}
}
}


It is compiled properly...But when i am trying to execute i am getting following exception

Exception: -

An unhandled exception of type 'System.Threading.ThreadStateException' occurred in mscorlib.dll

Additional information: Thread is running or terminated; it cannot restart.

Can u please give me the solution for this.....

Regards,
Vijay


Sure, try the following:

namespace Practice4
{
	public partial class Form1 : Form
	{
		private delegate void UpdateTextBoxHandler(String addMessage);

		public Form1()
		{
			InitializeComponent();
		}

		private void START_Click(object sender, EventArgs e)
		{
			Thread temp_thread = new Thread(function);

			temp_thread.Start();
		}

		void function()
		{
			if (textBox1.InvokeRequired)
				textBox1.Invoke(new UpdateTextBoxHandler(UpdateTextBox), "Vijay");
			else
				UpdateTextBox("Vijay");
		}

		private void UpdateTextBox(String message)
		{
			textBox1.Text += message;
		}
	}
}

I'm checking if invoking is required (i.e. because we're not in the thread that created the UI), if it is I use a delegate to set the text property. I'm using the same method to set the text property when invoke isn't required so that you have standard behaviour, e.g. if you called function() from the main thread. You could just use Invoke and not bother with the InvokeRequired property.

OK, what's happening here is you're continuously attempting to start the thread. Don't forget that when you start an operation on another thread the current thread gets back control immediately. This means your current thread will loop and try and start the thread again, because it's already running you then get your error. This is the code with the fault:

while (temp_flag == true)
{
    temp_thread.Start();
}

This is starting the thread and immediately looping and trying to start the thread again. I'm doubt this is your intention, what were you trying to achieve by using the temp_flag variable?

Hi macu,
Here temp_flag is used only to stop the process. But it is not happening so. I dont know whats the problem.

Anyway i will tell my requirement:-

I need to keep on calling the function "Function", so that it will keep on writing the text "Vijay" into the textbox. Once if i click exit button, the process should be terminated. This is what i want....

I think by seeing my program you can easily understand what i want....

So Can u please provide me any solution in order to achieve this....

Regards,
Vijay

I suspect you want to have the loop within your thread's function rather than within the code that starts the thread. That way your UI is still responsive and the second thread can continue adding text to the textbox. So your function may become something like:

void function()
{
    while (temp_flag)
    {
        if (textBox1.InvokeRequired)
            textBox1.Invoke(new UpdateTextBoxHandler(UpdateTextBox), "Vijay");
        else
            UpdateTextBox("Vijay");
    }
}

This way you have two threads in use, your main UI thread and the one you've created and the user is able to click exit to stop the second thread and exit the app. Alternatively you could make temp_thread a field of the form itself and call temp_thread.Abort in your exit click.

Hi macu,
Once again thank you very much for your brilliant solution. I have written the code exactly same as what you told. For your reference i am pasting the entire code here....

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Practice4
{
    public partial class Form1 : Form
    {
        static bool temp_flag = true;

        Thread temp_thread;

        private delegate void UpdateTextBoxHandler(String addMessage);

        public Form1()
        {
            InitializeComponent();
        }

        private void START_Click(object sender, EventArgs e)
        {
            temp_thread = new Thread(function);
            temp_thread.Start();
        }

        void function()
        {
            while (temp_flag == true)
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new UpdateTextBoxHandler(UpdateTextBox), "Vijay");
                }
                else
                {
                    UpdateTextBox("Vijay");
                }
            }
        }

        private void EXIT_Click(object sender, EventArgs e)
        {
            temp_flag = false;
            temp_thread.Abort();
            Application.Exit();
        }

        private void UpdateTextBox(String message)
        {
            textBox1.Text += message;
        }
    }
}

This time the program is keep on adding the "Vijay" to the textbox. But i
get the feeling that, the process could not be terminated even if i clicked the Exit button.
Just i want to stop the entire process as soon as i pressed Exit button. Can u please look into it and tell me whats the problem in the program.

Regards,
Vijay

The code looks fine to me, you're making doubly sure that the thread has been stopped. If you want to check you could go to Control Panel, Admin Tools, Performance. Add a new counter and choose Process, Thread Count and your project. When you run your project you'll see your thread pool thread count, when you click start this will go up by one as you've started a new thread and when you click exit you should see it go back down to where it was before you ran the app. Another test you could do is to write the current time to a file or something in your function and you'll see this stops when you exit.

Hi macu,
I went to the control panel,Admin Tools, Performance. After that i strucked. Where i need to add the new counter and where i need to choose the process.

Regards,
Vijay


The code looks fine to me, you're making doubly sure that the thread has been stopped. If you want to check you could go to Control Panel, Admin Tools, Performance. Add a new counter and choose Process, Thread Count and your project. When you run your project you'll see your thread pool thread count, when you click start this will go up by one as you've started a new thread and when you click exit you should see it go back down to where it was before you ran the app. Another test you could do is to write the current time to a file or something in your function and you'll see this stops when you exit.

Select the three default counters from underneath the graph and hit delete on each one to remove them. Click the + on the toolbar and you'll have a new dialog to add other counters. Choose Process in the top dropdown, then select thread count in the left listbox and then look for <your app name>.vshost in the right listbox and select it, then click Add.

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.