I am having a problem for a while
this line:
txtPastes.Text = (string)e.UserState;
throws a cross thread exception and I didn't find any solution
txtPastes - textbox
GuiUpdate - BackgroundWorker
lstAllPastes - list of string
private void GuiUpdate_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
while (lstAllPastes.Count == 0) ;
for (int i = 0; i < lstAllPastes[0].Length; i++)
{
GuiUpdate.ReportProgress(0, lstAllPastes[0].Substring(0, i));
Thread.Sleep(1);
}
lstAllPastes.RemoveAt(0);
}
}
private void GuiUpdate_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
txtPastes.Text = (string)e.UserState;
}
private void GuiUpdate_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
You cannot update a UI control from any thread other than the UI thread. Typically, the BackgroundWorker would take care of raising its ProgressChanged and RunWorkerCompleted events correctly on the UI thread. Since that doesn’t appear to be the case here, you could marshal your UI-updating logic to the UI thread yourself by using the Invoke method:
txtPastes.Invoke(new Action(() =>
{
// This code is executed on the UI thread.
txtPastes.Text = (string)e.UserState;
}));
If you’re on WPF, you would need to call Invoke on the control’s dispatcher:
txtPastes.Dispatcher.Invoke(new Action(() =>
{
txtPastes.Text = (string)e.UserState;
}));
Update: As Thomas Levesque and Hans Passant have mentioned, you should investigate the reason why your ProgressChanged event is not being raised on the UI thread. My suspicion is that you’re starting the BackgroundWorker too early in the application initialization lifecycle, which could lead to race conditions and possibly a NullReferenceException if the first ProgressChanged event is raised before your txtPastes textbox has been initialized.
Well, this is supposed to work of course. The cause of this exception is not visible in your snippet. What matters is exactly where and when the BackgroundWorker is started. Its RunWorkerAsync() method uses the SynchronizationContext.Current property to figure out what thread needs to execute the ProgressChanged event handler.
This can go wrong when:
You started the BGW too early, before the Application.Run() call. Winforms or WPF won't yet have had a chance to install its own synchronization provider.
You called the BGW's RunWorkerAsync() method in a worker thread. Only marshaling to the UI thread is supported, the message loop is the crucial ingredient to make running code on another thread work.
The form that has txtPastes control was created on another thread. With the BGW started on the UI thread that's still a thread mismatch
The form's Show() method was called on another thread. Which creates the native Windows window on the wrong thread.
Make sure you start the BackgroundWorker from the UI thread; if you do that, the ProgressChanged event will be raised on that thread, and the exception won't happen.
If you want to update yout GUI for example TextBox, you should read this article:
Update GUI from another thread
Related
I am trying to run a long running instance method on another thread from my UI, but still report progress back to the GUI thread to update a progress bar. I know there are a lot of ways to do this and many questions on SO regarding this. The long running instance method I have actually has two events of it's own. It has an event that fires on PropertyChanged, which is for reporting of the current work completed & current total work that needs to be completed. It also has an OperationCompleted event. I was planning on using a BackgroundWorker in my UI to run this long-running method on a separate thread. What I am trying to figure out is the following:
If I create event handlers for the PropertyChanged & OperationCompleted events, can I implement them to raise BackgroundWorker events? Will this allow them all run on the background thread and essentially simulate an event bubbling to the UI thread? Below is an example:
class GUI : Form
{
private BackgroundWorker back = new BackgroundWorker();
back.WorkerReportsProgress = true;
back.DoWork += new DoWorkEventHandler(myWork);
back.ProgressChanged += new ProgressChangedEventHandler(myWork_changed);
back.RunWorkerCompleted += RunWorkerCompletedEventHandler(myWork_completed);
/* GUI CODE OMITTED */
private void button_click(object sender, EventArgs e)
{
back.RunWorkerAsync();
}
private void myWork(object sender, DoWorkEventArgs e)
{
Syncer sync = new Syncer();
sync.PropertyChanged += new PropertyChangedEventHandler(sync_PropertyChanged);
sync.OperationCompleted += new EventHandler(sync_OperationCompleted);
sync.LongRunningMethod();
}
private void sync_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//calculations & logic as needed
back.ReportProgress(calculated);
}
//might not be necessary to implement because of how BackgroundWorker functions
private void sync_OperationCompleted(object sender, EventArgs e)
{
back.ReportProgress(100);
}
private void myWork_changed(object sender, ProgressChangedEventArgs e)
{
//update UI progress bar
}
private void myWork_completed(object sender, RunWorkerCompletedEventArgs e)
{
//tasks needed # completion such as hide progress bar
}
So will the events of the Syncer class fire on the same thread as the BackgroundWorker's DoWork() method? Is this thread safe? Criticism & alternative suggestions welcome!
The Syncer() class events will fire from whatever thread is actually raising them. That might be the same thread as the DoWork() handler, it might not be. We don't know the internal workings of the Syncer() class, so we can't tell from the code you've posted.
It's fine, however, to call ReportProgress() from the Syncer() events. Regardless of what thread they fire on, this will still result in the ProgressChanged() and RunWorkerCompleted() events being raised in the main UI thread (assuming the BackgroundWorker() was created by the main UI thread itself; which it was in this case).
You don't need to manually Invoke() anything, that's the whole point of using the BackgroundWorker() in the first place...to avoid the need to do that.
If you didn't use the BackgroundWorker() and "bubble" the events via its built-in events, and instead wrapped the Syncer() operation in a manual thread, then yes, you'd need to manually Invoke() updates to the GUI.
Events raised from the background worker thread will run on and block that thread and can in turn raise ReportProgress events which will also run on and block the worker thread so long as it can access a reference to the BackgroundWorker.
If you bear this in mind and use invoke calls to update the UI it should work fine.
I'm going crazy with a simple code in which I use a BackgroundWorker to automate the basic operations. Should I add a content to the clipboard.
After executing this code in the method of the BackgroundWorker:
Clipboard.SetText (splitpermutation [i]);
I get an error that explains the thread must be STA, but I do not understand how to do.
Here more code: (not all)
private readonly BackgroundWorker worker = new BackgroundWorker();
private void btnAvvia_Click(object sender, RoutedEventArgs e)
{
count = lstview.Items.Count;
startY = Convert.ToInt32(txtY.Text);
startX = Convert.ToInt32(txtX.Text);
finalY = Convert.ToInt32(txtFinalPositionY.Text);
finalX = Convert.ToInt32(txtFinalPositionX.Text);
incremento = Convert.ToInt32(txtIncremento.Text);
pausa = Convert.ToInt32(txtPausa.Text);
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
[...]
}
private void WorkFunction(object sender, DoWorkEventArgs e)
{
[...]
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
[...]
Clipboard.SetText(splitpermutation[i]);
[...]
}
}
You could marshal this to the UI thread to make it work:
else
{
[...]
this.Dispatcher.BeginInvoke(new Action(() => Clipboard.SetText(splitpermutation[i])));
[...]
}
The BackgroundWorker runs on the .NET thread pool. Thread pool threads run in the COM multi-threaded apartment. To use the clipboard, you must be running in a single-threaded apartment. You could create your own thread and set it to run in an STA, but it would probably be best to use Control.Invoke (or BeginInvoke) to get back onto a user-interface thread (which must be an STA thread).
The exception you're getting is because you're trying to do something on the UI thread from outside the UI thread (a BackgroundWorker, as the name implies, does something in the background, and for that it needs to create a separate thread).
While the answer posted by Reed (that is, by using Dispatcher.BeginInvoke) is one way to do avoid this exception, I'm wondering WHY you are trying to send something to the clipboard from the main work method in the first place...
The BackgroundWorker exposes events like ProgressChanged (which you can call periodically from your work method) or RunWorkerCompleted (which will fire when the main work method finishes).
Using Clipboard.SetText in either of these events should not cause the exception you're seeing, and this seems to be the preferable way of doing things on the UI thread when working with the BackgroundWorker.
private void button1_Click(object sender, EventArgs e)
{
PROGRESS_BAR.Minimum = 0;
PROGRESS_BAR.Maximum = 100;
PROGRESS_BAR.Value = 0;
for (int i = 0; i < 100; i++)
{
Thread t = new Thread(new ThreadStart(updateProgressBar));
t.IsBackground = true;
t.Start();
}
}
private void updateProgressBar()
{
PROGRESS_BAR.PerformStep();
Thread.Sleep(4000);
}
I always get this error:
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
I tried to search in google for solutions and unfortunately all of them didn't work for me. does any one know how to solve this?
thanks in advance..
You cannot interact with UI elements from non-UI thread.
You need to use code like
this.BeginInvoke((Action)(() => PROGRESS_BAR.PerformStep()));
You should use the BackgroundWorker component and its ProgressChanged event.
You can call the ReportProgress method inside the DoWork handler (which runs on the background thread), then update the progress bar in the ProgressChanged handler (which runs on the UI thread).
If you really want to do it yourself (without a BackgroundWorker), you can call BeginInvoke
All of your UI interaction, including callbacks, property sets, and method calls, must be on the same thread.
One of those callbacks can start another thread (or many threads) but they cannot directly update the UI. The way to handle the updates are through data properties. My processing thread would update a progress status property. This is throne read by the UI thread which has a timer for regular (100ms) updates of the progress bar.
If you do this, you will need a lock on any objects which are used to communicate e status updates (eg. Strings).
I have a ProgressBarWindow which has a progressbar and a cancel button on it which I use to report progress on file I/O. However, the UI Thread of the ProgressBarWindow and my main window both hang despite all the work being done in a backgroundworker. The progressbar is rendered, as is my main window, but does not update whilst the backgroundworker does its thing.
The following code is called at the very end of the constructor of the main window:
iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();
iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));
EventCountLogLinesProgressChanged() looks like this:
private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}
Here is a shortened version of ProgressBarWindow(the rest is just a couple of setters):
public partial class ProgressBarWindow : Window
{
public ProgressBarWindow()
{
InitializeComponent();
this.progressBar.Value = this.progressBar.Minimum = 0;
this.progressBar.Maximum = 100;
}
public double Value
{
get
{
return progressBar.Value;
}
set
{
this.progressBar.Value = value;
}
}
}
I've tried wrapping the value setter line in a dispatcher.invoke delegate but that gives me a stack overflow(I shouldn't have to have a dispatcher.invoke line anyway as backgroundworker calls ProgressChanged in the UI Thread, right?). I have checked msdn and googled but I can't seem to find anyone else with this problem.
EDIT Apologies, I did not realise my simplified code blocked the UI Thread, I get exactly the same behaviour despite using a backgroundworker so I erroneously assumed they were equivalent. I should have mentioned I was using a backgroundworker :P
You're blocking the UI thread, so it won't re-render the UI until your loop has finished.
Move the background processing into a separate thread, and use appropriate Dispatcher calls (or BackgroundWorker) to marshal UI update calls back to the UI thread.
If your progress bar is really just meant to be a timer, you could use one of the Timer classes to update it.
EDIT: Okay, now you've changed the code, it looks okay to me. It should be thread-safe as you're only changing the UI on the UI thread. Is your background worker definitely reporting progress periodically?
Listen to Jon Skeet,
or you could sometimes call Application.DoEvents() to make all UI updates in the same thread.
I have a pet project that I'm working on that has multiple worker threads. Outputting everything to the console is getting hard to follow, so I want to develop a UI that will have one output area per thread. I want to know the best way for the threads to send updates to the UI. I have two ideas:
1) Have each thread set a "DataUpdated" flag when new data is available, and have the UI periodically check for new data.
2) Create each thread with a callback to a UI Update(...) method to be called when new data becomes available.
I am currently leaning toward (2) for two reasons: I dislike the idea of "checking" each thread, and because this is my first multithreaded application and (2) seems simpler than it probably is. I want to know:
Which option is preferable in terms of simplicity and efficiency?
Do you have any tips for implementing (2) or something like it (i.e. more event-driven)?
You can easily implement (2) by creating BackgroundWorker components and doing the work in their DoWork handlers:
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += /* your background work here */;
bw.ProgressChanged += /* your UI update method here */;
bw.RunWorkerAsync();
Each BackgroundWorker can report progress to the UI thread by calling ReportProgress: although this is primarily designed for reporting progress on a bounded process, that's not mandatory -- you can pass your own custom data as well if that's what your UI update requires. You would call ReportProgress from your DoWork handler.
The nice thing about BackgroundWorker is that it takes care of a lot of messy cross-threading details for you. It also conforms to the event-driven model of updates which you (rightly) prefer to explicit callbacks.
In most cases the easiest thing to do would be to use the BackgroundWorker component as suggested in itowlson's answer, and I would strongly suggest using that approach if possible. If, for some reason, you can't use a BackgroundWorker component for your purpose, such as if you're developing with .Net 1.1 (yikes!) or with compact framework, then you might need to use an alternative approach:
With Winform controls you have to avoid modifying controls on any thread other than the thread that originally created the control. The BackgroundWorker component handles this for you, but if you aren't using that, then you can and should use the InvokeRequired property and Invoke method found on the System.Windows.Forms.Control class. Below is an example that uses this property and method:
public partial class MultithreadingForm : Form
{
public MultithreadingForm()
{
InitializeComponent();
}
// a simple button event handler that starts a worker thread
private void btnDoWork_Click(object sender, EventArgs e)
{
Thread t = new Thread(WorkerMethod);
t.Start();
}
private void ReportProgress(string message)
{
// check whether or not the current thread is the main UI thread
// if not, InvokeRequired will be true
if (this.InvokeRequired)
{
// create a delegate pointing back to this same function
// the Invoke method will cause the delegate to be invoked on the main UI thread
this.Invoke(new Action<string>(ReportProgress), message);
}
else
{
// txtOutput is a UI control, therefore it must be updated by the main UI thread
if (string.IsNullOrEmpty(this.txtOutput.Text))
this.txtOutput.Text = message;
else
this.txtOutput.Text += "\r\n" + message;
}
}
// a generic method that does work and reports progress
private void WorkerMethod()
{
// step 1
// ...
ReportProgress("Step 1 completed");
// step 2
// ...
ReportProgress("Step 2 completed");
// step 3
// ...
ReportProgress("Step 3 completed");
}
}
I vote for #2 as well but with BackgroundWorkers instead of System.Threading.Threads.
You can have your worker threads raise events and have the main UI thread add event handlers. You need to be careful you're not raising too many events as it could get ugly if your worker threads are raising multiple events per second.
This article gives a quick overview.
The preferred way to implement multithreading in your application is to use the BackgroundWorker component. The BackgroundWorker component uses an event-driven model for multithreading. The worker thread runs your DoWork event handler, and the thread that creates your controls runs your ProgressChanged and RunWorkerCompleted event handlers.
When you update your UI controls in the ProgressChanged eventhandler, they are automatically updated on main thread which will prevent you from getting crossthread exceptions.
Look here for an example on how to use the backgroundworker.
If you're creating your own threads (non BackgroundWorker or ThreadPool threads) you can pass a callback method from your main thread that's called from the worker thread. This also lets you pass arguments to the callback and even return a value (such as a go/no-go flag). In your callback you update the UI through the target control's Dispatcher:
public void UpdateUI(object arg)
{
controlToUpdate.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal
, new System.Windows.Threading.DispatcherOperationCallback(delegate
{
controToUpdate.property = arg;
return null;
}), null);
}
}