How to fix 'Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on'
By FoxLearn 12/23/2024 7:03:40 AM 529
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.
What is the difference between Invoke and BeginInvoke?
- Invoke is synchronous and blocks the calling thread until the operation completes.
- BeginInvoke is asynchronous, adding the operation to the Dispatcher’s event queue with a specified priority, and returns control to the calling thread 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");
- How to use BlockingCollection in C#
- Calculating the Distance Between Two Coordinates in C#
- Could Not Find an Implementation of the Query Pattern
- Fixing Invalid Parameter Type in Attribute Constructor
- Objects added to a BindingSource’s list must all be of the same type
- How to use dictionary with tuples in C#
- How to convert a dictionary to a list in C#
- Dictionary with multiple values per key in C#