Related
Dears,
I am investigating multithreads programming. I would like to extend a DGV to be Multithread Safe. Code seems to be working fine but I am not sure about the use of "lock" statement:
public class MultiThreadsDataGridView:DataGridView
{
public void UpdateCell(int Row, int Column, string Value) {
lock (this)
{
Invoke(
new Action(
() => Rows[Row].Cells[Column].Value = Value
)
);
}
}
public void AddRow(params object[] value) {
lock(this){
Invoke(
new Action(
() => Rows.Add(value)
)
);
}
}
}
Will the "lock", used in this way, be working as expected?
Thanks
As a general rule, it is not allowed accesing the UI elements withing other thread. That being said, it can be done using the Control.Invoke function or a BackgroundWorker.
Your code will work as expected indeed, but will perform poorly due to innecesary locking.
Check the official documentation for further information How to make thread-safe calls to controls (Windows Forms .NET)
This is the example of the documentation using Control.Invoke() (I always found background workers a pain in the ass). They use TextBox, should be identical with DataGridView
private void button1_Click(object sender, EventArgs e)
{
var threadParameters = new System.Threading.ThreadStart(delegate { WriteTextSafe("This text was set safely."); });
var thread2 = new System.Threading.Thread(threadParameters);
thread2.Start();
}
public void WriteTextSafe(string text)
{
if (textBox1.InvokeRequired)
{
// Call this same method but append THREAD2 to the text
Action safeWrite = delegate { WriteTextSafe($"{text} (THREAD2)"); };
textBox1.Invoke(safeWrite);
}
else
textBox1.Text = text;
}
Which is the simplest way to update a Label from another Thread?
I have a Form running on thread1, and from that I'm starting another thread (thread2).
While thread2 is processing some files I would like to update a Label on the Form with the current status of thread2's work.
How could I do that?
The simplest way is an anonymous method passed into Label.Invoke:
// Running on the worker thread
string newText = "abc";
form.Label.Invoke((MethodInvoker)delegate {
// Running on the UI thread
form.Label.Text = newText;
});
// Back on the worker thread
Notice that Invoke blocks execution until it completes--this is synchronous code. The question doesn't ask about asynchronous code, but there is lots of content on Stack Overflow about writing asynchronous code when you want to learn about it.
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!
Handling long work
Since .NET 4.5 and C# 5.0 you should use Task-based Asynchronous Pattern (TAP) along with async-await keywords in all areas (including the GUI):
TAP is the recommended asynchronous design pattern for new development
instead of Asynchronous Programming Model (APM) and Event-based Asynchronous Pattern (EAP) (the latter includes the BackgroundWorker Class).
Then, the recommended solution for new development is:
Asynchronous implementation of an event handler (Yes, that's all):
private async void Button_Clicked(object sender, EventArgs e)
{
var progress = new Progress<string>(s => label.Text = s);
await Task.Factory.StartNew(() => SecondThreadConcern.LongWork(progress),
TaskCreationOptions.LongRunning);
label.Text = "completed";
}
Implementation of the second thread that notifies the UI thread:
class SecondThreadConcern
{
public static void LongWork(IProgress<string> progress)
{
// Perform a long running work...
for (var i = 0; i < 10; i++)
{
Task.Delay(500).Wait();
progress.Report(i.ToString());
}
}
}
Notice the following:
Short and clean code written in sequential manner without callbacks and explicit threads.
Task instead of Thread.
async keyword, that allows to use await which in turn prevent the event handler from reaching the completion state till the task finished and in the meantime doesn't block the UI thread.
Progress class (see IProgress Interface) that supports Separation of Concerns (SoC) design principle and doesn't require explicit dispatcher and invoking. It uses the current SynchronizationContext from its creation place (here the UI thread).
TaskCreationOptions.LongRunning that hints to do not queue the task into ThreadPool.
For a more verbose examples see: The Future of C#: Good things come to those who 'await' by Joseph Albahari.
See also about UI Threading Model concept.
Handling exceptions
The below snippet is an example of how to handle exceptions and toggle button's Enabled property to prevent multiple clicks during background execution.
private async void Button_Click(object sender, EventArgs e)
{
button.Enabled = false;
try
{
var progress = new Progress<string>(s => button.Text = s);
await Task.Run(() => SecondThreadConcern.FailingWork(progress));
button.Text = "Completed";
}
catch(Exception exception)
{
button.Text = "Failed: " + exception.Message;
}
button.Enabled = true;
}
class SecondThreadConcern
{
public static void FailingWork(IProgress<string> progress)
{
progress.Report("I will fail in...");
Task.Delay(500).Wait();
for (var i = 0; i < 3; i++)
{
progress.Report((3 - i).ToString());
Task.Delay(500).Wait();
}
throw new Exception("Oops...");
}
}
Variation of Marc Gravell's simplest solution for .NET 4:
control.Invoke((MethodInvoker) (() => control.Text = "new text"));
Or use Action delegate instead:
control.Invoke(new Action(() => control.Text = "new text"));
See here for a comparison of the two: MethodInvoker vs Action for Control.BeginInvoke
Fire and forget extension method for .NET 3.5+
using System;
using System.Windows.Forms;
public static class ControlExtensions
{
/// <summary>
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
/// </summary>
/// <param name="control"></param>
/// <param name="code"></param>
public static void UIThread(this Control #this, Action code)
{
if (#this.InvokeRequired)
{
#this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
This can be called using the following line of code:
this.UIThread(() => this.myLabel.Text = "Text Goes Here");
This is the classic way you should do this:
using System;
using System.Windows.Forms;
using System.Threading;
namespace Test
{
public partial class UIThread : Form
{
Worker worker;
Thread workerThread;
public UIThread()
{
InitializeComponent();
worker = new Worker();
worker.ProgressChanged += new EventHandler<ProgressChangedArgs>(OnWorkerProgressChanged);
workerThread = new Thread(new ThreadStart(worker.StartWork));
workerThread.Start();
}
private void OnWorkerProgressChanged(object sender, ProgressChangedArgs e)
{
// Cross thread - so you don't get the cross-threading exception
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
OnWorkerProgressChanged(sender, e);
});
return;
}
// Change control
this.label1.Text = e.Progress;
}
}
public class Worker
{
public event EventHandler<ProgressChangedArgs> ProgressChanged;
protected void OnProgressChanged(ProgressChangedArgs e)
{
if(ProgressChanged!=null)
{
ProgressChanged(this,e);
}
}
public void StartWork()
{
Thread.Sleep(100);
OnProgressChanged(new ProgressChangedArgs("Progress Changed"));
Thread.Sleep(100);
}
}
public class ProgressChangedArgs : EventArgs
{
public string Progress {get;private set;}
public ProgressChangedArgs(string progress)
{
Progress = progress;
}
}
}
Your worker thread has an event. Your UI thread starts off another thread to do the work and hooks up that worker event so you can display the state of the worker thread.
Then in the UI you need to cross threads to change the actual control... like a label or a progress bar.
The simple solution is to use Control.Invoke.
void DoSomething()
{
if (InvokeRequired) {
Invoke(new MethodInvoker(updateGUI));
} else {
// Do Something
updateGUI();
}
}
void updateGUI() {
// update gui here
}
Threading code is often buggy and always hard to test. You don't need to write threading code to update the user interface from a background task. Just use the BackgroundWorker class to run the task and its ReportProgress method to update the user interface. Usually, you just report a percentage complete, but there's another overload that includes a state object. Here's an example that just reports a string object:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "A");
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "B");
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "C");
}
private void backgroundWorker1_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
label1.Text = e.UserState.ToString();
}
That's fine if you always want to update the same field. If you've got more complicated updates to make, you could define a class to represent the UI state and pass it to the ReportProgress method.
One final thing, be sure to set the WorkerReportsProgress flag, or the ReportProgress method will be completely ignored.
The vast majority of answers use Control.Invoke which is a race condition waiting to happen. For example, consider the accepted answer:
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
If the user closes the form just before this.Invoke is called (remember, this is the Form object), an ObjectDisposedException will be likely fired.
The solution is to use SynchronizationContext, specifically SynchronizationContext.Current as hamilton.danielb suggests (other answers rely on specific SynchronizationContext implementations which is completely unnecessary). I would slightly modify his code to use SynchronizationContext.Post rather than SynchronizationContext.Send though (as there's typically no need for the worker thread to wait):
public partial class MyForm : Form
{
private readonly SynchronizationContext _context;
public MyForm()
{
_context = SynchronizationContext.Current
...
}
private MethodOnOtherThread()
{
...
_context.Post(status => someLabel.Text = newText,null);
}
}
Note that on .NET 4.0 and up you should really be using tasks for async operations. See n-san's answer for the equivalent task-based approach (using TaskScheduler.FromCurrentSynchronizationContext).
Finally, on .NET 4.5 and up you can also use Progress<T> (which basically captures SynchronizationContext.Current upon its creation) as demonstrated by Ryszard Dżegan's for cases where the long-running operation needs to run UI code while still working.
You'll have to make sure that the update happens on the correct thread; the UI thread.
In order to do this, you'll have to Invoke the event-handler instead of calling it directly.
You can do this by raising your event like this:
(The code is typed here out of my head, so I haven't checked for correct syntax, etc., but it should get you going.)
if( MyEvent != null )
{
Delegate[] eventHandlers = MyEvent.GetInvocationList();
foreach( Delegate d in eventHandlers )
{
// Check whether the target of the delegate implements
// ISynchronizeInvoke (Winforms controls do), and see
// if a context-switch is required.
ISynchronizeInvoke target = d.Target as ISynchronizeInvoke;
if( target != null && target.InvokeRequired )
{
target.Invoke (d, ... );
}
else
{
d.DynamicInvoke ( ... );
}
}
}
Note that the code above will not work on WPF projects, since WPF controls do not implement the ISynchronizeInvoke interface.
In order to make sure that the code above works with Windows Forms and WPF, and all other platforms, you can have a look at the AsyncOperation, AsyncOperationManager and SynchronizationContext classes.
In order to easily raise events this way, I've created an extension method, which allows me to simplify raising an event by just calling:
MyEvent.Raise(this, EventArgs.Empty);
Of course, you can also make use of the BackGroundWorker class, which will abstract this matter for you.
Because of the triviality of the scenario I would actually have the UI thread poll for the status. I think you will find that it can be quite elegant.
public class MyForm : Form
{
private volatile string m_Text = "";
private System.Timers.Timer m_Timer;
private MyForm()
{
m_Timer = new System.Timers.Timer();
m_Timer.SynchronizingObject = this;
m_Timer.Interval = 1000;
m_Timer.Elapsed += (s, a) => { MyProgressLabel.Text = m_Text; };
m_Timer.Start();
var thread = new Thread(WorkerThread);
thread.Start();
}
private void WorkerThread()
{
while (...)
{
// Periodically publish progress information.
m_Text = "Still working...";
}
}
}
The approach avoids the marshaling operation required when using the ISynchronizeInvoke.Invoke and ISynchronizeInvoke.BeginInvoke methods. There is nothing wrong with using the marshaling technique, but there are a couple of caveats you need to be aware of.
Make sure you do not call BeginInvoke too frequently or it could overrun the message pump.
Calling Invoke on the worker thread is a blocking call. It will temporarily halt the work being done in that thread.
The strategy I propose in this answer reverses the communication roles of the threads. Instead of the worker thread pushing the data the UI thread polls for it. This a common pattern used in many scenarios. Since all you are wanting to do is display progress information from the worker thread then I think you will find that this solution is a great alternative to the marshaling solution. It has the following advantages.
The UI and worker threads remain loosely coupled as opposed to the Control.Invoke or Control.BeginInvoke approach which tightly couples them.
The UI thread will not impede the progress of the worker thread.
The worker thread cannot dominate the time the UI thread spends updating.
The intervals at which the UI and worker threads perform operations can remain independent.
The worker thread cannot overrun the UI thread's message pump.
The UI thread gets to dictate when and how often the UI gets updated.
You'll need to Invoke the method on the GUI thread. You can do that by calling Control.Invoke.
For example:
delegate void UpdateLabelDelegate (string message);
void UpdateLabel (string message)
{
if (InvokeRequired)
{
Invoke (new UpdateLabelDelegate (UpdateLabel), message);
return;
}
MyLabelControl.Text = message;
}
None of the Invoke stuff in the previous answers is necessary.
You need to look at WindowsFormsSynchronizationContext:
// In the main thread
WindowsFormsSynchronizationContext mUiContext = new WindowsFormsSynchronizationContext();
...
// In some non-UI Thread
// Causes an update in the GUI thread.
mUiContext.Post(UpdateGUI, userData);
...
void UpdateGUI(object userData)
{
// Update your GUI controls here
}
This one is similar to the solution above using .NET Framework 3.0, but it solved the issue of compile-time safety support.
public static class ControlExtension
{
delegate void SetPropertyValueHandler<TResult>(Control souce, Expression<Func<Control, TResult>> selector, TResult value);
public static void SetPropertyValue<TResult>(this Control source, Expression<Func<Control, TResult>> selector, TResult value)
{
if (source.InvokeRequired)
{
var del = new SetPropertyValueHandler<TResult>(SetPropertyValue);
source.Invoke(del, new object[]{ source, selector, value});
}
else
{
var propInfo = ((MemberExpression)selector.Body).Member as PropertyInfo;
propInfo.SetValue(source, value, null);
}
}
}
To use:
this.lblTimeDisplay.SetPropertyValue(a => a.Text, "some string");
this.lblTimeDisplay.SetPropertyValue(a => a.Visible, false);
The compiler will fail if the user passes the wrong data type.
this.lblTimeDisplay.SetPropertyValue(a => a.Visible, "sometext");
Salvete! Having searched for this question, I found the answers by FrankG and Oregon Ghost to be the easiest most useful to me. Now, I code in Visual Basic and ran this snippet through a convertor; so I'm not sure quite how it turns out.
I have a dialog form called form_Diagnostics, which has a richtext box, called updateDiagWindow, which I am using as a sort of logging display. I needed to be able to update its text from all threads. The extra lines allow the window to automatically scroll to the newest lines.
And so, I can now update the display with one line, from anywhere in the entire program in the manner which you think it would work without any threading:
form_Diagnostics.updateDiagWindow(whatmessage);
Main Code (put this inside of your form's class code):
#region "---------Update Diag Window Text------------------------------------"
// This sub allows the diag window to be updated by all threads
public void updateDiagWindow(string whatmessage)
{
var _with1 = diagwindow;
if (_with1.InvokeRequired) {
_with1.Invoke(new UpdateDiagDelegate(UpdateDiag), whatmessage);
} else {
UpdateDiag(whatmessage);
}
}
// This next line makes the private UpdateDiagWindow available to all threads
private delegate void UpdateDiagDelegate(string whatmessage);
private void UpdateDiag(string whatmessage)
{
var _with2 = diagwindow;
_with2.appendtext(whatmessage);
_with2.SelectionStart = _with2.Text.Length;
_with2.ScrollToCaret();
}
#endregion
Label lblText; //initialized elsewhere
void AssignLabel(string text)
{
if (InvokeRequired)
{
BeginInvoke((Action<string>)AssignLabel, text);
return;
}
lblText.Text = text;
}
Note that BeginInvoke() is preferred over Invoke() because it's less likely to cause deadlocks (however, this is not an issue here when just assigning text to a label):
When using Invoke() you are waiting for the method to return. Now, it may be that you do something in the invoked code that will need to wait for the thread, which may not be immediately obvious if it's buried in some functions that you are calling, which itself may happen indirectly via event handlers. So you would be waiting for the thread, the thread would be waiting for you and you are deadlocked.
This actually caused some of our released software to hang. It was easy enough to fix by replacing Invoke() with BeginInvoke(). Unless you have a need for synchronous operation, which may be the case if you need a return value, use BeginInvoke().
For many purposes it's as simple as this:
public delegate void serviceGUIDelegate();
private void updateGUI()
{
this.Invoke(new serviceGUIDelegate(serviceGUI));
}
"serviceGUI()" is a GUI level method within the form (this) that can change as many controls as you want. Call "updateGUI()" from the other thread. Parameters can be added to pass values, or (probably faster) use class scope variables with locks on them as required if there is any possibility of a clash between threads accessing them that could cause instability. Use BeginInvoke instead of Invoke if the non-GUI thread is time critical (keeping Brian Gideon's warning in mind).
When I encountered the same issue I sought help from Google, but rather than give me a simple solution it confused me more by giving examples of MethodInvoker and blah blah blah. So I decided to solve it on my own. Here is my solution:
Make a delegate like this:
Public delegate void LabelDelegate(string s);
void Updatelabel(string text)
{
if (label.InvokeRequired)
{
LabelDelegate LDEL = new LabelDelegate(Updatelabel);
label.Invoke(LDEL, text);
}
else
label.Text = text
}
You can call this function in a new thread like this
Thread th = new Thread(() => Updatelabel("Hello World"));
th.start();
Don't be confused with Thread(() => .....). I use an anonymous function or lambda expression when I work on a thread. To reduce the lines of code you can use the ThreadStart(..) method too which I am not supposed to explain here.
This in my C# 3.0 variation of Ian Kemp's solution:
public static void SetPropertyInGuiThread<C,V>(this C control, Expression<Func<C, V>> property, V value) where C : Control
{
var memberExpression = property.Body as MemberExpression;
if (memberExpression == null)
throw new ArgumentException("The 'property' expression must specify a property on the control.");
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("The 'property' expression must specify a property on the control.");
if (control.InvokeRequired)
control.Invoke(
(Action<C, Expression<Func<C, V>>, V>)SetPropertyInGuiThread,
new object[] { control, property, value }
);
else
propertyInfo.SetValue(control, value, null);
}
You call it like this:
myButton.SetPropertyInGuiThread(b => b.Text, "Click Me!")
It adds null-checking to the result of the "as MemberExpression".
It improves the static type-safety.
Otherwise, the original is a very nice solution.
Most of the other answers are a little complex for me on this question (I'm new to C#), so I am writing mine:
I have a WPF application and have defined a worker as below:
Issue:
BackgroundWorker workerAllocator;
workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1) {
// This is my DoWork function.
// It is given as an anonymous function, instead of a separate DoWork function
// I need to update a message to textbox (txtLog) from this thread function
// Want to write below line, to update UI
txt.Text = "my message"
// But it fails with:
// 'System.InvalidOperationException':
// "The calling thread cannot access this object because a different thread owns it"
}
Solution:
workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1)
{
// The below single line works
txtLog.Dispatcher.BeginInvoke((Action)(() => txtLog.Text = "my message"));
}
I am yet to find out what the above line means, but it works.
For WinForms:
Solution:
txtLog.Invoke((MethodInvoker)delegate
{
txtLog.Text = "my message";
});
Simply use something like this:
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = e.ProgressPercentage; // runs on UI thread
});
My version is to insert one line of recursive "mantra":
For no arguments:
void Aaaaaaa()
{
if (InvokeRequired) { Invoke(new Action(Aaaaaaa)); return; } //1 line of mantra
// Your code!
}
For a function that has arguments:
void Bbb(int x, string text)
{
if (InvokeRequired) { Invoke(new Action<int, string>(Bbb), new[] { x, text }); return; }
// Your code!
}
THAT is IT.
Some argumentation: Usually it is bad for code readability to put {} after an if () statement in one line. But in this case it is routine all-the-same "mantra". It doesn't break code readability if this method is consistent over the project. And it saves your code from littering (one line of code instead of five).
As you see if(InvokeRequired) {something long} you just know "this function is safe to call from another thread".
You may use the already-existing delegate Action:
private void UpdateMethod()
{
if (InvokeRequired)
{
Invoke(new Action(UpdateMethod));
}
}
And yet another generic Control extension aproach..
First add an extension method for objects of type Control
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
and call like this from another thread to access a Control named object1 in UI-thread:
object1.InvokeIfRequired(c => { c.Visible = true; });
object1.InvokeIfRequired(c => { c.Text = "ABC"; });
..or like this
object1.InvokeIfRequired(c =>
{
c.Text = "ABC";
c.Visible = true;
}
);
Create a class variable:
SynchronizationContext _context;
Set it in the constructor that creates your UI:
var _context = SynchronizationContext.Current;
When you want to update the label:
_context.Send(status =>{
// UPDATE LABEL
}, null);
You must use invoke and delegate
private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
Try to refresh the label using this
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
The simplest way in WPF applications is:
this.Dispatcher.Invoke((Action)(() =>
{
// This refers to a form in a WPF application
val1 = textBox.Text; // Access the UI
}));
When you're in the UI thread you could ask it for its synchronization context task scheduler. It would give you a TaskScheduler that schedules everything on the UI thread.
Then you can chain your tasks so that when the result is ready then another task (which is scheduled on the UI thread) picks it and assigns it to a label.
public partial class MyForm : Form
{
private readonly TaskScheduler _uiTaskScheduler;
public MyForm()
{
InitializeComponent();
_uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private void buttonRunAsyncOperation_Click(object sender, EventArgs e)
{
RunAsyncOperation();
}
private void RunAsyncOperation()
{
var task = new Task<string>(LengthyComputation);
task.ContinueWith(antecedent =>
UpdateResultLabel(antecedent.Result), _uiTaskScheduler);
task.Start();
}
private string LengthyComputation()
{
Thread.Sleep(3000);
return "47";
}
private void UpdateResultLabel(string text)
{
labelResult.Text = text;
}
}
This works for tasks (not threads) which are the preferred way of writing concurrent code now.
For example, access a control other than in the current thread:
Speed_Threshold = 30;
textOutput.Invoke(new EventHandler(delegate
{
lblThreshold.Text = Speed_Threshold.ToString();
}));
There the lblThreshold is a Label and Speed_Threshold is a global variable.
Which is the simplest way to update a Label from another Thread?
I have a Form running on thread1, and from that I'm starting another thread (thread2).
While thread2 is processing some files I would like to update a Label on the Form with the current status of thread2's work.
How could I do that?
The simplest way is an anonymous method passed into Label.Invoke:
// Running on the worker thread
string newText = "abc";
form.Label.Invoke((MethodInvoker)delegate {
// Running on the UI thread
form.Label.Text = newText;
});
// Back on the worker thread
Notice that Invoke blocks execution until it completes--this is synchronous code. The question doesn't ask about asynchronous code, but there is lots of content on Stack Overflow about writing asynchronous code when you want to learn about it.
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!
Handling long work
Since .NET 4.5 and C# 5.0 you should use Task-based Asynchronous Pattern (TAP) along with async-await keywords in all areas (including the GUI):
TAP is the recommended asynchronous design pattern for new development
instead of Asynchronous Programming Model (APM) and Event-based Asynchronous Pattern (EAP) (the latter includes the BackgroundWorker Class).
Then, the recommended solution for new development is:
Asynchronous implementation of an event handler (Yes, that's all):
private async void Button_Clicked(object sender, EventArgs e)
{
var progress = new Progress<string>(s => label.Text = s);
await Task.Factory.StartNew(() => SecondThreadConcern.LongWork(progress),
TaskCreationOptions.LongRunning);
label.Text = "completed";
}
Implementation of the second thread that notifies the UI thread:
class SecondThreadConcern
{
public static void LongWork(IProgress<string> progress)
{
// Perform a long running work...
for (var i = 0; i < 10; i++)
{
Task.Delay(500).Wait();
progress.Report(i.ToString());
}
}
}
Notice the following:
Short and clean code written in sequential manner without callbacks and explicit threads.
Task instead of Thread.
async keyword, that allows to use await which in turn prevent the event handler from reaching the completion state till the task finished and in the meantime doesn't block the UI thread.
Progress class (see IProgress Interface) that supports Separation of Concerns (SoC) design principle and doesn't require explicit dispatcher and invoking. It uses the current SynchronizationContext from its creation place (here the UI thread).
TaskCreationOptions.LongRunning that hints to do not queue the task into ThreadPool.
For a more verbose examples see: The Future of C#: Good things come to those who 'await' by Joseph Albahari.
See also about UI Threading Model concept.
Handling exceptions
The below snippet is an example of how to handle exceptions and toggle button's Enabled property to prevent multiple clicks during background execution.
private async void Button_Click(object sender, EventArgs e)
{
button.Enabled = false;
try
{
var progress = new Progress<string>(s => button.Text = s);
await Task.Run(() => SecondThreadConcern.FailingWork(progress));
button.Text = "Completed";
}
catch(Exception exception)
{
button.Text = "Failed: " + exception.Message;
}
button.Enabled = true;
}
class SecondThreadConcern
{
public static void FailingWork(IProgress<string> progress)
{
progress.Report("I will fail in...");
Task.Delay(500).Wait();
for (var i = 0; i < 3; i++)
{
progress.Report((3 - i).ToString());
Task.Delay(500).Wait();
}
throw new Exception("Oops...");
}
}
Variation of Marc Gravell's simplest solution for .NET 4:
control.Invoke((MethodInvoker) (() => control.Text = "new text"));
Or use Action delegate instead:
control.Invoke(new Action(() => control.Text = "new text"));
See here for a comparison of the two: MethodInvoker vs Action for Control.BeginInvoke
Fire and forget extension method for .NET 3.5+
using System;
using System.Windows.Forms;
public static class ControlExtensions
{
/// <summary>
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
/// </summary>
/// <param name="control"></param>
/// <param name="code"></param>
public static void UIThread(this Control #this, Action code)
{
if (#this.InvokeRequired)
{
#this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}
This can be called using the following line of code:
this.UIThread(() => this.myLabel.Text = "Text Goes Here");
This is the classic way you should do this:
using System;
using System.Windows.Forms;
using System.Threading;
namespace Test
{
public partial class UIThread : Form
{
Worker worker;
Thread workerThread;
public UIThread()
{
InitializeComponent();
worker = new Worker();
worker.ProgressChanged += new EventHandler<ProgressChangedArgs>(OnWorkerProgressChanged);
workerThread = new Thread(new ThreadStart(worker.StartWork));
workerThread.Start();
}
private void OnWorkerProgressChanged(object sender, ProgressChangedArgs e)
{
// Cross thread - so you don't get the cross-threading exception
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
OnWorkerProgressChanged(sender, e);
});
return;
}
// Change control
this.label1.Text = e.Progress;
}
}
public class Worker
{
public event EventHandler<ProgressChangedArgs> ProgressChanged;
protected void OnProgressChanged(ProgressChangedArgs e)
{
if(ProgressChanged!=null)
{
ProgressChanged(this,e);
}
}
public void StartWork()
{
Thread.Sleep(100);
OnProgressChanged(new ProgressChangedArgs("Progress Changed"));
Thread.Sleep(100);
}
}
public class ProgressChangedArgs : EventArgs
{
public string Progress {get;private set;}
public ProgressChangedArgs(string progress)
{
Progress = progress;
}
}
}
Your worker thread has an event. Your UI thread starts off another thread to do the work and hooks up that worker event so you can display the state of the worker thread.
Then in the UI you need to cross threads to change the actual control... like a label or a progress bar.
The simple solution is to use Control.Invoke.
void DoSomething()
{
if (InvokeRequired) {
Invoke(new MethodInvoker(updateGUI));
} else {
// Do Something
updateGUI();
}
}
void updateGUI() {
// update gui here
}
Threading code is often buggy and always hard to test. You don't need to write threading code to update the user interface from a background task. Just use the BackgroundWorker class to run the task and its ReportProgress method to update the user interface. Usually, you just report a percentage complete, but there's another overload that includes a state object. Here's an example that just reports a string object:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "A");
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "B");
Thread.Sleep(5000);
backgroundWorker1.ReportProgress(0, "C");
}
private void backgroundWorker1_ProgressChanged(
object sender,
ProgressChangedEventArgs e)
{
label1.Text = e.UserState.ToString();
}
That's fine if you always want to update the same field. If you've got more complicated updates to make, you could define a class to represent the UI state and pass it to the ReportProgress method.
One final thing, be sure to set the WorkerReportsProgress flag, or the ReportProgress method will be completely ignored.
The vast majority of answers use Control.Invoke which is a race condition waiting to happen. For example, consider the accepted answer:
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
If the user closes the form just before this.Invoke is called (remember, this is the Form object), an ObjectDisposedException will be likely fired.
The solution is to use SynchronizationContext, specifically SynchronizationContext.Current as hamilton.danielb suggests (other answers rely on specific SynchronizationContext implementations which is completely unnecessary). I would slightly modify his code to use SynchronizationContext.Post rather than SynchronizationContext.Send though (as there's typically no need for the worker thread to wait):
public partial class MyForm : Form
{
private readonly SynchronizationContext _context;
public MyForm()
{
_context = SynchronizationContext.Current
...
}
private MethodOnOtherThread()
{
...
_context.Post(status => someLabel.Text = newText,null);
}
}
Note that on .NET 4.0 and up you should really be using tasks for async operations. See n-san's answer for the equivalent task-based approach (using TaskScheduler.FromCurrentSynchronizationContext).
Finally, on .NET 4.5 and up you can also use Progress<T> (which basically captures SynchronizationContext.Current upon its creation) as demonstrated by Ryszard Dżegan's for cases where the long-running operation needs to run UI code while still working.
You'll have to make sure that the update happens on the correct thread; the UI thread.
In order to do this, you'll have to Invoke the event-handler instead of calling it directly.
You can do this by raising your event like this:
(The code is typed here out of my head, so I haven't checked for correct syntax, etc., but it should get you going.)
if( MyEvent != null )
{
Delegate[] eventHandlers = MyEvent.GetInvocationList();
foreach( Delegate d in eventHandlers )
{
// Check whether the target of the delegate implements
// ISynchronizeInvoke (Winforms controls do), and see
// if a context-switch is required.
ISynchronizeInvoke target = d.Target as ISynchronizeInvoke;
if( target != null && target.InvokeRequired )
{
target.Invoke (d, ... );
}
else
{
d.DynamicInvoke ( ... );
}
}
}
Note that the code above will not work on WPF projects, since WPF controls do not implement the ISynchronizeInvoke interface.
In order to make sure that the code above works with Windows Forms and WPF, and all other platforms, you can have a look at the AsyncOperation, AsyncOperationManager and SynchronizationContext classes.
In order to easily raise events this way, I've created an extension method, which allows me to simplify raising an event by just calling:
MyEvent.Raise(this, EventArgs.Empty);
Of course, you can also make use of the BackGroundWorker class, which will abstract this matter for you.
Because of the triviality of the scenario I would actually have the UI thread poll for the status. I think you will find that it can be quite elegant.
public class MyForm : Form
{
private volatile string m_Text = "";
private System.Timers.Timer m_Timer;
private MyForm()
{
m_Timer = new System.Timers.Timer();
m_Timer.SynchronizingObject = this;
m_Timer.Interval = 1000;
m_Timer.Elapsed += (s, a) => { MyProgressLabel.Text = m_Text; };
m_Timer.Start();
var thread = new Thread(WorkerThread);
thread.Start();
}
private void WorkerThread()
{
while (...)
{
// Periodically publish progress information.
m_Text = "Still working...";
}
}
}
The approach avoids the marshaling operation required when using the ISynchronizeInvoke.Invoke and ISynchronizeInvoke.BeginInvoke methods. There is nothing wrong with using the marshaling technique, but there are a couple of caveats you need to be aware of.
Make sure you do not call BeginInvoke too frequently or it could overrun the message pump.
Calling Invoke on the worker thread is a blocking call. It will temporarily halt the work being done in that thread.
The strategy I propose in this answer reverses the communication roles of the threads. Instead of the worker thread pushing the data the UI thread polls for it. This a common pattern used in many scenarios. Since all you are wanting to do is display progress information from the worker thread then I think you will find that this solution is a great alternative to the marshaling solution. It has the following advantages.
The UI and worker threads remain loosely coupled as opposed to the Control.Invoke or Control.BeginInvoke approach which tightly couples them.
The UI thread will not impede the progress of the worker thread.
The worker thread cannot dominate the time the UI thread spends updating.
The intervals at which the UI and worker threads perform operations can remain independent.
The worker thread cannot overrun the UI thread's message pump.
The UI thread gets to dictate when and how often the UI gets updated.
You'll need to Invoke the method on the GUI thread. You can do that by calling Control.Invoke.
For example:
delegate void UpdateLabelDelegate (string message);
void UpdateLabel (string message)
{
if (InvokeRequired)
{
Invoke (new UpdateLabelDelegate (UpdateLabel), message);
return;
}
MyLabelControl.Text = message;
}
None of the Invoke stuff in the previous answers is necessary.
You need to look at WindowsFormsSynchronizationContext:
// In the main thread
WindowsFormsSynchronizationContext mUiContext = new WindowsFormsSynchronizationContext();
...
// In some non-UI Thread
// Causes an update in the GUI thread.
mUiContext.Post(UpdateGUI, userData);
...
void UpdateGUI(object userData)
{
// Update your GUI controls here
}
This one is similar to the solution above using .NET Framework 3.0, but it solved the issue of compile-time safety support.
public static class ControlExtension
{
delegate void SetPropertyValueHandler<TResult>(Control souce, Expression<Func<Control, TResult>> selector, TResult value);
public static void SetPropertyValue<TResult>(this Control source, Expression<Func<Control, TResult>> selector, TResult value)
{
if (source.InvokeRequired)
{
var del = new SetPropertyValueHandler<TResult>(SetPropertyValue);
source.Invoke(del, new object[]{ source, selector, value});
}
else
{
var propInfo = ((MemberExpression)selector.Body).Member as PropertyInfo;
propInfo.SetValue(source, value, null);
}
}
}
To use:
this.lblTimeDisplay.SetPropertyValue(a => a.Text, "some string");
this.lblTimeDisplay.SetPropertyValue(a => a.Visible, false);
The compiler will fail if the user passes the wrong data type.
this.lblTimeDisplay.SetPropertyValue(a => a.Visible, "sometext");
Salvete! Having searched for this question, I found the answers by FrankG and Oregon Ghost to be the easiest most useful to me. Now, I code in Visual Basic and ran this snippet through a convertor; so I'm not sure quite how it turns out.
I have a dialog form called form_Diagnostics, which has a richtext box, called updateDiagWindow, which I am using as a sort of logging display. I needed to be able to update its text from all threads. The extra lines allow the window to automatically scroll to the newest lines.
And so, I can now update the display with one line, from anywhere in the entire program in the manner which you think it would work without any threading:
form_Diagnostics.updateDiagWindow(whatmessage);
Main Code (put this inside of your form's class code):
#region "---------Update Diag Window Text------------------------------------"
// This sub allows the diag window to be updated by all threads
public void updateDiagWindow(string whatmessage)
{
var _with1 = diagwindow;
if (_with1.InvokeRequired) {
_with1.Invoke(new UpdateDiagDelegate(UpdateDiag), whatmessage);
} else {
UpdateDiag(whatmessage);
}
}
// This next line makes the private UpdateDiagWindow available to all threads
private delegate void UpdateDiagDelegate(string whatmessage);
private void UpdateDiag(string whatmessage)
{
var _with2 = diagwindow;
_with2.appendtext(whatmessage);
_with2.SelectionStart = _with2.Text.Length;
_with2.ScrollToCaret();
}
#endregion
Label lblText; //initialized elsewhere
void AssignLabel(string text)
{
if (InvokeRequired)
{
BeginInvoke((Action<string>)AssignLabel, text);
return;
}
lblText.Text = text;
}
Note that BeginInvoke() is preferred over Invoke() because it's less likely to cause deadlocks (however, this is not an issue here when just assigning text to a label):
When using Invoke() you are waiting for the method to return. Now, it may be that you do something in the invoked code that will need to wait for the thread, which may not be immediately obvious if it's buried in some functions that you are calling, which itself may happen indirectly via event handlers. So you would be waiting for the thread, the thread would be waiting for you and you are deadlocked.
This actually caused some of our released software to hang. It was easy enough to fix by replacing Invoke() with BeginInvoke(). Unless you have a need for synchronous operation, which may be the case if you need a return value, use BeginInvoke().
For many purposes it's as simple as this:
public delegate void serviceGUIDelegate();
private void updateGUI()
{
this.Invoke(new serviceGUIDelegate(serviceGUI));
}
"serviceGUI()" is a GUI level method within the form (this) that can change as many controls as you want. Call "updateGUI()" from the other thread. Parameters can be added to pass values, or (probably faster) use class scope variables with locks on them as required if there is any possibility of a clash between threads accessing them that could cause instability. Use BeginInvoke instead of Invoke if the non-GUI thread is time critical (keeping Brian Gideon's warning in mind).
When I encountered the same issue I sought help from Google, but rather than give me a simple solution it confused me more by giving examples of MethodInvoker and blah blah blah. So I decided to solve it on my own. Here is my solution:
Make a delegate like this:
Public delegate void LabelDelegate(string s);
void Updatelabel(string text)
{
if (label.InvokeRequired)
{
LabelDelegate LDEL = new LabelDelegate(Updatelabel);
label.Invoke(LDEL, text);
}
else
label.Text = text
}
You can call this function in a new thread like this
Thread th = new Thread(() => Updatelabel("Hello World"));
th.start();
Don't be confused with Thread(() => .....). I use an anonymous function or lambda expression when I work on a thread. To reduce the lines of code you can use the ThreadStart(..) method too which I am not supposed to explain here.
This in my C# 3.0 variation of Ian Kemp's solution:
public static void SetPropertyInGuiThread<C,V>(this C control, Expression<Func<C, V>> property, V value) where C : Control
{
var memberExpression = property.Body as MemberExpression;
if (memberExpression == null)
throw new ArgumentException("The 'property' expression must specify a property on the control.");
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
throw new ArgumentException("The 'property' expression must specify a property on the control.");
if (control.InvokeRequired)
control.Invoke(
(Action<C, Expression<Func<C, V>>, V>)SetPropertyInGuiThread,
new object[] { control, property, value }
);
else
propertyInfo.SetValue(control, value, null);
}
You call it like this:
myButton.SetPropertyInGuiThread(b => b.Text, "Click Me!")
It adds null-checking to the result of the "as MemberExpression".
It improves the static type-safety.
Otherwise, the original is a very nice solution.
Most of the other answers are a little complex for me on this question (I'm new to C#), so I am writing mine:
I have a WPF application and have defined a worker as below:
Issue:
BackgroundWorker workerAllocator;
workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1) {
// This is my DoWork function.
// It is given as an anonymous function, instead of a separate DoWork function
// I need to update a message to textbox (txtLog) from this thread function
// Want to write below line, to update UI
txt.Text = "my message"
// But it fails with:
// 'System.InvalidOperationException':
// "The calling thread cannot access this object because a different thread owns it"
}
Solution:
workerAllocator.DoWork += delegate (object sender1, DoWorkEventArgs e1)
{
// The below single line works
txtLog.Dispatcher.BeginInvoke((Action)(() => txtLog.Text = "my message"));
}
I am yet to find out what the above line means, but it works.
For WinForms:
Solution:
txtLog.Invoke((MethodInvoker)delegate
{
txtLog.Text = "my message";
});
Simply use something like this:
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = e.ProgressPercentage; // runs on UI thread
});
My version is to insert one line of recursive "mantra":
For no arguments:
void Aaaaaaa()
{
if (InvokeRequired) { Invoke(new Action(Aaaaaaa)); return; } //1 line of mantra
// Your code!
}
For a function that has arguments:
void Bbb(int x, string text)
{
if (InvokeRequired) { Invoke(new Action<int, string>(Bbb), new[] { x, text }); return; }
// Your code!
}
THAT is IT.
Some argumentation: Usually it is bad for code readability to put {} after an if () statement in one line. But in this case it is routine all-the-same "mantra". It doesn't break code readability if this method is consistent over the project. And it saves your code from littering (one line of code instead of five).
As you see if(InvokeRequired) {something long} you just know "this function is safe to call from another thread".
You may use the already-existing delegate Action:
private void UpdateMethod()
{
if (InvokeRequired)
{
Invoke(new Action(UpdateMethod));
}
}
And yet another generic Control extension aproach..
First add an extension method for objects of type Control
public static void InvokeIfRequired<T>(this T c, Action<T> action) where T : Control
{
if (c.InvokeRequired)
{
c.Invoke(new Action(() => action(c)));
}
else
{
action(c);
}
}
and call like this from another thread to access a Control named object1 in UI-thread:
object1.InvokeIfRequired(c => { c.Visible = true; });
object1.InvokeIfRequired(c => { c.Text = "ABC"; });
..or like this
object1.InvokeIfRequired(c =>
{
c.Text = "ABC";
c.Visible = true;
}
);
Create a class variable:
SynchronizationContext _context;
Set it in the constructor that creates your UI:
var _context = SynchronizationContext.Current;
When you want to update the label:
_context.Send(status =>{
// UPDATE LABEL
}, null);
You must use invoke and delegate
private delegate void MyLabelDelegate();
label1.Invoke( new MyLabelDelegate(){ label1.Text += 1; });
Try to refresh the label using this
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
The simplest way in WPF applications is:
this.Dispatcher.Invoke((Action)(() =>
{
// This refers to a form in a WPF application
val1 = textBox.Text; // Access the UI
}));
When you're in the UI thread you could ask it for its synchronization context task scheduler. It would give you a TaskScheduler that schedules everything on the UI thread.
Then you can chain your tasks so that when the result is ready then another task (which is scheduled on the UI thread) picks it and assigns it to a label.
public partial class MyForm : Form
{
private readonly TaskScheduler _uiTaskScheduler;
public MyForm()
{
InitializeComponent();
_uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private void buttonRunAsyncOperation_Click(object sender, EventArgs e)
{
RunAsyncOperation();
}
private void RunAsyncOperation()
{
var task = new Task<string>(LengthyComputation);
task.ContinueWith(antecedent =>
UpdateResultLabel(antecedent.Result), _uiTaskScheduler);
task.Start();
}
private string LengthyComputation()
{
Thread.Sleep(3000);
return "47";
}
private void UpdateResultLabel(string text)
{
labelResult.Text = text;
}
}
This works for tasks (not threads) which are the preferred way of writing concurrent code now.
For example, access a control other than in the current thread:
Speed_Threshold = 30;
textOutput.Invoke(new EventHandler(delegate
{
lblThreshold.Text = Speed_Threshold.ToString();
}));
There the lblThreshold is a Label and Speed_Threshold is a global variable.
In regular WinAPI you can send a message to a window inside your application using PostMessage which would not wait for the message to be processed, it returns immediately.
Now in my window I receive this message which is called in the same UI thread where I can manipulate some other UI controls.
How can I simulate this behavior in .NET WinForms?
I know I can use Delegate.BeginInvoke which will call my method async, but it won't be executed in same UI thread, and any access to the UI controls would raise an exception. I know I can use Control.Invoke to change the UI inside that method, but that's too much to write code, I want do not worry with this and work same way as in WinAPI.
I have such a code
public delegate void DoDelegate();
private DoDelegate d;
public Form1()
{
InitializeComponent();
d = new DoDelegate(Do);
}
private void button1_Click(object sender, EventArgs e)
{
d.BeginInvoke(ar =>
{
AsyncResult result = (AsyncResult)ar;
DoDelegate dd = (DoDelegate)result.AsyncDelegate;
dd.EndInvoke(ar);
}, null);
}
public void Do()
{
Action a = () =>
{
for (int i = 0; i < 10; i++)
{
label1.Text = "Item " + i;
Thread.Sleep(1000);
}
};
if (InvokeRequired)
Invoke(a);
else a();
}
which blocks the main thread even though is called in a separate one. I know why, because I use Control.Invoke on whole method and I should use it only around setting the .Text property, but again, that's too much, is easy forget use Invoke and then all crashes.
So, basically, how do I call a method async, which won't create any issues to access UI without Invoke mechanism, same same I do using PostMessage?
Ideas?
I use this extension method:
public static void InvokeIfRequired(this Control control, Action action)
{
if (control.InvokeRequired)
control.Invoke(action);
else
action();
}
Which I use on any multithreaded code accesing the UI. In your case, it'd do like:
label1.InvokeIfRequired(() => { label1.Text = "Item " + i });
Note that if you are using it widely for just single changes to a control, it might be wise to have an overload of the extension method like:
public static void InvokeIfRequired(this Control control, Action<Control> action)
{
if (control.InvokeRequired)
control.Invoke(new Action(() => action(control)));
else
action(control);
}
So you can do:
label1.InvokeIfRequired(x => { x.Text = "Item " + i });
Not having to repeat the control on the lambda expression
Having an issue getting data from a form control from within a thread. I need to access the data, then modify it.
The following doesn't work I'm aware, but I used it as an example to see what I'm trying to do.
Thread t = new Thread(() => {
foreach (ListViewItem row in listView1.Items)
{
row.SubItems[0].Text = "Checking";
Thread.Sleep(2000);
}
});
t.Start();
I've read the MSDN documentation on making thread safe calls, but I can't seem to get access to the actual list view control. The examples I've seen use delegates to "update" controls, but I need access to the data in the controls before I update the data in them.
Edit:
I'd like to see an example, or a link to an example, detailing how to get access to the ListView1 form control in the foreach loop.
You need to use Invoke pattern, in order to be able to access any UI element or its properties from the thread other then main UI thread. All UI controls on windows allways run on the main thread, to handle message chain correctly between OS and UI presented on the screen.
The (quickly written) example I was talking about, this assumes that you do not need to really use the controls, I included a function that is based off tigran's link
Thread t = new Thread(() => UpdateText(listBox1.Items));
t.Start();
private void UpdateText(ListBox.ObjectCollection items)
{
foreach (var item in items)
{
SetText(item.ToString());
Thread.Sleep(1000);
}
}
You can't do what you want to do. All accesses and updates to UI must go in UI thread. It is mandatory.
What you can do is writing your raw data into cache on UI then processing your cache and callbacks to UI after all processings are finished.
public class CacheData {
private object row;
public CacheData(object row)
{
//initialization
}
public static ProcessedData ProcessData(List<CacheData> dataToProcess)
{
return new ProcessedData();
}
}
public class ProcessedData { }
private void AccessControl()
{
ListView list = new ListView();
List<CacheData> cache = new List<CacheData>();
//Filling the cache on UI
foreach (var row in list.Items)
{
cache.Add(new CacheData(row));
}
//Process result async and then invoke on UI back
System.ComponentModel.BackgroundWorker bg = new System.ComponentModel.BackgroundWorker();
bg.DoWork += (sender,e) => {
e.Result = CacheData.ProcessData(cache);
};
bg.RunWorkerCompleted += (sender, e) => {
//If you have started your bg from UI result will be invoked in UI automatically.
//Otherwise you should invoke it manually.
list.Dispatcher.Invoke((Action) delegate {
//pass e.result to control here)
},null);
};
bg.RunWorkerAsync();
}
Method 1:
Use Invoke like Tigran describes.
For Winforms this would look like:
Thread t = new Thread(() =>
{
if (!Dispatcher.CurrentDispatcher.CheckAccess())
{
Dispatcher.CurrentDispatcher.BeginInvoke(
new Action(() =>
{
foreach (ListViewItem row in listView1.Items)
{
row.SubItems[0].Text = "Checking";
Thread.Sleep(2000);
}
}),
DispatcherPriority.ApplicationIdle,
null);
}
else
{
foreach (ListViewItem row in listView1.Items)
{
row.SubItems[0].Text = "Checking";
Thread.Sleep(2000);
}
}
});
t.Start();
The CheckAccess() Call returns true if called from the UI-Thread otherwise false.
The Dispatcher Class is located in the "System.Windows.Threading" Namespace in the "WindowsBase" NET. Assembly
Dispatcher info copied from: https://stackoverflow.com/a/4429009/1469035
Edit: Changed code to WinForms.
Edit: Code Fixed.
Method 2:
Use a Callback:
Untested Code:
public partial class Form1 : Form
{
private delegate void SetCallback(ListViewItem row, string text);
public Form1()
{
InitializeComponent();
}
private void SomeMethod()
{
Thread t = new Thread(() =>
{
foreach (ListViewItem row in listView1.Items)
{
if (listView1.InvokeRequired)
{
SetCallback d = new SetCallback(SetText);
this.Invoke(d, new object[] { row, "Checking" });
}
Thread.Sleep(2000);
}
});
t.Start();
}
private void SetText(ListViewItem row, string text)
{
row.SubItems[0].Text = text;
}
}
AFAIK readonly Access to Controls from Threads other than the UI-Thread is allowed in Winforms. So you can check any Control-Property you want and pass the required information to the Delegate.
And even if Reading doents work that way, you can just make another Delegate that has a return value. The Invoke() Method returns an object:
Similar to this:
private delegate object GetCallback(ListViewItem row);
private object o;
...
GetCallback g = new GetCallback(GetText);
o = this.Invoke(g, new object[] { row });
private string GetText(ListViewItem row)
{
return row.SubItems[0].Text;
}
Derived From: Link