How to fix 'Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on'
By FoxLearn 7/8/2024 2:50:27 AM 307
In Windows Forms, UI controls are not thread-safe and should only be accessed from the UI thread.
To fix this error, you generally need to ensure that any UI updates or interactions with controls are performed on the UI thread.
In .NET (C# or VB.NET), you can use the Invoke
or BeginInvoke
methods of a control to marshal the execution of a delegate onto the thread that owns the control.
// c# update a label from a different thread private void UpdateLabel(string text) { if (label1.InvokeRequired) { // c# Invoke or BeginInvoke the action on the UI thread label1.Invoke((Action)(() => label1.Text = text)); } else { // Directly update the label if already on the UI thread label1.Text = text; } }
InvokeRequired
checks if you're on the UI thread.
Invoke
executes the given delegate on the UI thread and waits for it to complete.
BeginInvoke
executes the delegate asynchronously on the UI thread and returns immediately.
If you're using .NET Framework, another approach is to use BackgroundWorker
, which simplifies interacting with UI controls from a separate thread.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { string result = DoSomeThing(); // Report progress and pass result to UI thread backgroundWorker1.ReportProgress(0, result); } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // c# update UI controls based on progress or result label1.Text = e.UserState as string; }
If you're using .NET Core or .NET 5+, you can use Task.Run
for background operations and async/await
to marshal back to the UI thread:
private async void Button_Click(object sender, EventArgs e) { // Perform background operation string result = await Task.Run(() => DoSomeThing()); // Update UI controls label1.Text = result; }
You can also create an extension method that allows you to update cross-threaded data in c# which usually involves ensuring that operations that modify UI controls are executed on the UI thread.
public static class CrossThreadExtensions { public static void Invoke<TControlType>(this TControlType control, Action<TControlType> action) where TControlType : Control { if (control.InvokeRequired) control.Invoke(new Action(() => action(control))); else action(control); } }
You can simply do this.
textbox1.Invoke(t => t.Text = "c# cross-thread");