Writing to a Textbox from Another Thread

Writing to a TextBox from another thread?

On your MainForm make a function to set the textbox the checks the InvokeRequired

public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] {value});
return;
}
ActiveForm.Text += value;
}

although in your static method you can't just call.

WindowsFormsApplication1.Form1.AppendTextBox("hi. ");

you have to have a static reference to the Form1 somewhere, but this isn't really recommended or necessary, can you just make your SampleFunction not static if so then you can just call

AppendTextBox("hi. ");

It will append on a differnt thread and get marshalled to the UI using the Invoke call if required.

Full Sample

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(SampleFunction).Start();
}

public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] {value});
return;
}
textBox1.Text += value;
}

void SampleFunction()
{
// Gets executed on a seperate thread and
// doesn't block the UI while sleeping
for(int i = 0; i<5; i++)
{
AppendTextBox("hi. ");
Thread.Sleep(1000);
}
}
}

How do I write to a textbox from 3 threads?

As I know, you can directly manage the text box only if you're in the main window thread.
Since you event (Thread_Notify) can be called from other threads, you can't use it directly because if it runs in a thread different from the main window one, it will throw an Exception.

For let it work, you have to write the notify in this way:

private void Thread_Notify(string message)
{
Dispatcher.Invoke(new Action(() =>
{
tbLogs.Text += message;
}), DispatcherPriority.Background);
}

Get text from TextBox from another thread

Generally speaking, it shouldn't be necessary to access the UI elements from worker threads.

You should change your approach. I suppose you're on .NET Framework 4.5 or newer, so there's a right pattern for you: TAP, more commonly known as async/await.

With this pattern, you don't care about the threads. The Framework cares about them for you. Your task is to tell the compiler, what needs to be performed as an asynchronous action.

Just an example - change the event handler of your Button's Click event to something like this:

async void LoginButton_Click(object sender, EventArgs e)
{
// This runs on the UI thread
string login = loginTextBox.Text;
string password = pwdTextBox.Text;

loginButton.Enabled = false;

// This will be executed asynchronously, in your case - on a worker thread
bool success = await Task.Run(() => myLoginProcessor.Login(login, password));

// This runs again on the UI thread, so you can safely access your controls
if (success)
{
labelResult.Text = "Successfully logged in.";
}
else
{
labelResult.Text = "Invalid credentials.";
}

loginButton.Enabled = true;
}

Writing to a textBox using two threads

Here's an example that uses two threads to write random numbers to a multi-line text box. As Brandon and Jon B noted, you need to use Invoke() to serialize the calls to the GUI thread.

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

Random m_random = new Random((int)DateTime.Now.Ticks);
ManualResetEvent m_stopThreadsEvent = new ManualResetEvent(false);

private void buttonStart_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(new ThreadStart(ThreadOne));
Thread t2 = new Thread(new ThreadStart(ThreadTwo));

t1.Start();
t2.Start();
}

private void ThreadOne()
{
for(;;)
{
int n = m_random.Next(1000);
AppendText(String.Format("One: {0}\r\n", n));
if(m_stopThreadsEvent.WaitOne(n))
{
break;
}
}
}

private void ThreadTwo()
{
for(;;)
{
int n = m_random.Next(1000);
AppendText(String.Format("Two: {0}\r\n", n));
if(m_stopThreadsEvent.WaitOne(n))
{
break;
}
}
}

delegate void AppendTextDelegate(string text);

private void AppendText(string text)
{
if(textBoxLog.InvokeRequired)
{
textBoxLog.Invoke(new AppendTextDelegate(this.AppendText), new object[] { text });
}
else
{
textBoxLog.Text = textBoxLog.Text += text;
}
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
m_stopThreadsEvent.Set();
}
}

append to textbox from another thread

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.

Accessing text box from other thread


delegate void SetTextCallback(TextBox textBox, string text);
private void SetText(TextBox textBox, string text)
{
if (textBox.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] {textBox, text});
}
else
{
textBox.Text = text;
}
}

writing in textbox from anoter class (on another thread)

Without knowing enough about your application I'll suggest that what you need is to invoke an event in the class that is handled by the form. What happens is like this:

  1. Class has an event.
  2. Form starts up and instantiates class.
  3. Form assigns a handler to the event in the class.
  4. Class does whatever it needs to do, until it reaches the point where it needs to communicate with the form.
  5. Class raises the event.
  6. The handler in the form gets executed and the textbox changes.

So in the code of the class you'll need to add some definitions:

public delegate void FinishedEventHandler(object sender, string ValueToReturn);
public event FinishedEventHandler Finished;

The first is a delegate with the signature of the event. By convention the first argument is always a reference to the instance of the class itself, and the rest are the values you want to return. The second is the actual event.

Now, in the function that does whatever processing the class does we need to raise the event when appropriate:

void DoSomething()
{
.
.
.
if(Finished!=null) Finished(this, "some value");
}

The if clause is used to make sure that someone is actually handling our event, otherwise we might get an exception.

Now let's take a look at the form. We need to add a function that handles the event. It needs to have the same signature as the delegate we defined earlier. Within that function we do whatever changes we need to the form in light of the values we get back:

private void FinishedEventHandler(object sender, string ValueToReturn)
{
TextBox1.Text = ValueToReturn;
}

Now we're ready to use all that plumbing we just created. First we add the handler to the event, then we can call the class's processing functions.

MyClass.Finished += FinishedEventHandler;
MyClass.DoSomething();

Here's a more detailed tutorial:

http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx

Write on textbox in a thread (TASK) in WPF Application

Your error is because UI elements, such as a TextBox, can only be modified from the UI thread.

In order to fix this issue, change:

textBox.AppendText("Test");

to

Dispatcher.BeginInvoke((Action)(() => textBox.AppendText("Test")));

This will cause textBox.AppendText("Test"); to be executed on the UI thread, rather then the background thread that your task is executing on.



Related Topics



Leave a reply



Submit