How to Update Textbox on Gui from Another Thread

How do I update the GUI from another thread?

For .NET 2.0, here's a nice bit of code I wrote that does exactly what you want, and works for any property on a Control:

private delegate void SetControlPropertyThreadSafeDelegate(
Control control,
string propertyName,
object propertyValue);

public static void SetControlPropertyThreadSafe(
Control control,
string propertyName,
object propertyValue)
{
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate
(SetControlPropertyThreadSafe),
new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(
propertyName,
BindingFlags.SetProperty,
null,
control,
new object[] { propertyValue });
}
}

Call it like this:

// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);

If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the Control class, which would then simplify the call to:

myLabel.SetPropertyThreadSafe("Text", status);

UPDATE 05/10/2010:

For .NET 3.0 you should use this code:

private delegate void SetPropertyThreadSafeDelegate<TResult>(
Control @this,
Expression<Func<TResult>> property,
TResult value);

public static void SetPropertyThreadSafe<TResult>(
this Control @this,
Expression<Func<TResult>> property,
TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member
as PropertyInfo;

if (propertyInfo == null ||
!@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
@this.GetType().GetProperty(
propertyInfo.Name,
propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}

if (@this.InvokeRequired)
{
@this.Invoke(new SetPropertyThreadSafeDelegate<TResult>
(SetPropertyThreadSafe),
new object[] { @this, property, value });
}
else
{
@this.GetType().InvokeMember(
propertyInfo.Name,
BindingFlags.SetProperty,
null,
@this,
new object[] { value });
}
}

which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:

// status has to be of type string or this will fail to compile
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status);

Not only is the property name now checked at compile time, the property's type is as well, so it's impossible to (for example) assign a string value to a boolean property, and hence cause a runtime exception.

Unfortunately this doesn't stop anyone from doing stupid things such as passing in another Control's property and value, so the following will happily compile:

myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);

Hence I added the runtime checks to ensure that the passed-in property does actually belong to the Control that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.

If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!

Update Text Box Contents from another Thread, in another Class. C#, WPF

One way is to add an event handler to your PerformaceClass like this:

 public class PerformanceClass
{
public event EventHandler<PerformanceEventArgs> DataUpdate;

....
public void CPUThread()
{
int i = 0;
while (i++ < 5)
{
string cpuCount = getCPUUsage();
OnDataUpdate(cpuCount);
System.Threading.Thread.Sleep(500);

}
}

private void OnDataUpdate(string data)
{
var handler = DataUpdate;
if (handler != null)
{
handler(this, new PerformanceEventArgs(data));
}
}
}

public class PerformanceEventArgs: EventArgs
{
public string Data { get; private set; }
public PerformanceEventArgs(string data)
{
Data = data;
}
}

Then use it in your main like this:

public MainWindow()
{
InitializeComponent();

//start a new thread to obtain CPU usage
PerformanceClass pc = new PerformanceClass();
pc.DataUpdate += HandleDataUpdate;
Thread pcThread = new Thread(pc.CPUThread);
pcThread.Start();
}

private void HandleDataUpdate(object sender, PerformanceEventArgs e)
{
// dispatch the modification to the text box to the UI thread (main window dispatcher)
Dispatcher.BeginInvoke(DispatcherPriority.Normal, () => { txt_CPU.Text = e.Data });
}

Note that I fixed the typo in the PerformanceClass (missing n).

Updating a textbox in main GUI from a thread (created on button click) in cli

It is safe to use .NET Thread^ in this scenario. Inside your thread1 method use Control::BeginInvoke or Control::Invoke like @AlexF mentioned. Here you have an example from C#.

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);
}
}
}

Can't update text box in UI from server thread

Change your UpdateText(string text) to this:

    private void UpdateText(string text)
{
if(textBox5.InvokeRequired)
{
Action a = () => UpdateText(text);
Invoke(a);
}
else
textBox5.Text = text;
}

This will invoke the textbox if required.

Invoke From MSDN

The Invoke method searches up the control's parent chain until it
finds a control or form that has a window handle if the current
control's underlying window handle does not exist yet. If no
appropriate handle can be found, the Invoke method will throw an
exception. Exceptions that are raised during the call will be
propagated back to the caller.

WebForm: Update textbox from another thread

You usually don't.

Code Behind is executed on the server, then the resulting Page is sent to the client/browser. At that point, the life cycle of your C# Code Behind is over.

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);
}


Related Topics



Leave a reply



Submit