I am trying to write a simple multithreaded program in C#. It has a button pressing which creates a new label on form, and then a for loop runs displaying loop value in label. So if you press button 3 times, it will create 3 threads with 3 labels on form with loop.
When I press the button once, it works fine. But when I press it more than once to create more labels, it runs into following problems:
As soon as button is pressed more than once, it stops the loop in previous thread and runs loop of new thread. If it is multithreaded then it should not stop first loop.
When loop of second label is finished, it gives following error
Object reference not set to an instance of an object
Here is my complete code. The line which throws error is at the end "mylabel[tcount].Text = i.ToString();".
Screenshot of program: http://i.imgur.com/IFMIs.png
Screenshot of code http://i.imgur.com/sIXtc.png
namespace WindowsFormsApplication2{
public partial class Form1 : Form{
public Form1(){
InitializeComponent();
}
private int tcount = 0;
private int y_point = 0;
Thread[] threads = new Thread[5];
Label[] mylabel = new Label[5];
private void button1_Click(object sender, EventArgs e){
threads[tcount] = new Thread(new ThreadStart(work));
threads[tcount].Start();
}
private void work(){
if (this.InvokeRequired){
this.Invoke(new MethodInvoker(delegate{
mylabel[tcount] = new Label();
mylabel[tcount].Text = "label" + tcount;
mylabel[tcount].Location = new System.Drawing.Point(0, y_point + 15);
y_point += 25;
this.Controls.Add(mylabel[tcount]);
for (int i = 0; i < 10000; i++){
mylabel[tcount].Text = i.ToString();
Application.DoEvents();
}
}));
}
tcount++;
}
}
}
If it is multithreaded then it should not stop first loop.
But it is not multithreaded.
this.Invoke(new MethodInvoker(delegate{
This switches via invoker the context back to the UI Thread, so while you open a lot of threads in the background, you basically then put all the processing back into one main thread.
This:
Application.DoEvents();
Then gives other queued work a chance. Still only on the UI thread.
And finally you never parametrize the threads so they all work on the same variables. There is only one non thread save (no lock, no volatile) variable named tCount - bang.
Basically you demonstrate:
Your problem is not solvable multi threaded - any UI element manipulation HAS to happen on the UI thread (which is why you invoke) and as this is all you do you basically can not multithread.
You lack a basic understanding on how UI programs work with threads and the message pump.
You lack a basic understanding on variable scoing and access patterns between threads.
Back to reading documentation I would say.
The problem is the scope of tcount, as all threads acces the same instance of it, so as soon as the second thread starts the first thread also wirtes into the second label.
Also you invoke your whole worker method which will let it run in the UI-Thread again -> not actually multithreaded...
Your worker method should look something like this:
private void work()
{
int tIndex = tCount; //store the index of this thread
tcount++;
mylabel[tIndex] = new Label();
mylabel[tIndex].Text = "label" + tcount;
mylabel[tIndex].Location = new System.Drawing.Point(0, y_point + 15);
y_point += 25;
Invoke((MethodInvoker)delegate() { this.Controls.Add(mylabel[tIndex]); });
for (int i = 0; i < 10000; i++)
{
//doWork
Invoke((MethodInvoker)delegate() { mylabel[tIndex].Text = i.ToString(); });
}
}
Jep, you need to copy tcount to a local variable. As soon as you hit the button twice while a thread has not yet terminated, it is manipulating the second one.
Related
I'm working with a WinForm from which all processes that I need are steered. Now I'm trying to integrate a BackgroundWorker with a ProgressBar and a cancellation button into my code. I want it to be locally around my code and not in a separate method. To test this, a new form is created with a progress bar (not active yet) and a button to stop a for-loop. However, the code is not working (and the progress bar is not even included yet). The form freezes immediately (see image) so I can't test the cancel button. The for-loop, however, is executed and "Done: " + l.ToString() is shown. How can I solve this?
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
}
public void testcancel() // Test method which is triggered manually
{
int l = 0;
MetingProgress metingProgress = new MetingProgress();
metingProgress.btnCancelmeting.Click += new EventHandler(stopMeasurement);
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (worker.CancellationPending)
break;
}
MessageBox.Show("Done: " + l.ToString());
};
worker.RunWorkerAsync();
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
metingProgress.Dispose();
MessageBox.Show("All done");
}
The form freezes immediately
this is because you have a while loop still running on the main thread! So the form will not be responsive. This is called buisy waiting. You will not be able to call the CancelAsync method.
One solution could be to remove the while-loop and place the cancel call into the button event code:
void stopMeasurement(object sender, EventArgs e)
{
stopMeas = true;
worker.CancelAsync();
}
What you have basically done is: you created a second cancelation token. So another possibility could be to use only stopMeas to cancel the background operation:
worker.DoWork += (sender, args) =>
{
for (int k = 0; k < 10; k++)
{
Thread.Sleep(1000);
l++;
if (stopMeas)
break;
}
string mes = stopMeas ? "Done: " + l.ToString() : "Task aborted!";
MessageBox.Show(mes);
};
EDIT: also this line:
metingProgress.Dispose();
might lead to an ObjectDisposed exception. If the background process is still running and trying to update your progressbar and you already dispose the form. You should remove this line and leave it to the garbage collector.
This code is your problem:
while (worker.IsBusy)
{
if (stopMeas)
worker.CancelAsync();
}
Your GUI-Thread is in that loop until your worker is done.
You need to make your worker instance be reachable from within the EventHandler and call worker.CancelAsync() from there.
Outside this , I personally would improve the code in 2 steps:
Move the whole BackgroundWorker into the MetingProgress class and make its constructor take a delegate for the actual work implementation.
Use TAP (Task Async Pattern) , i.e. async/await Task with Progress and CancellationToken.
Fairly frustrating since this seems to be well documented and the fact that I accomplished this before, but can't duplicate the same success. Sorry, I'll try to relate it all clearly.
Visual Studio, C# Form, One Main Form has text fields, among other widgets.
At one point we have the concept that we are "running" and therefore gathering data.
For the moment, I started a one second timer so that I can update simulated data into some fields. Eventually that one second timer will take the more rapid data and update it only once per second to the screen, that's the request for the application right now we update at the rate we receive which is a little over 70 Hz, they don't want it that way. In addition some other statistics will be computed and those should be the field updates. Therefore being simple I'm trying to just generate random data and update those fields at the 1 Hz rate. And then expand from that point.
Definition and management of the timer: (this is all within the same class MainScreen)
System.Timers.Timer oneSecondTimer;
public UInt32 run_time = 0;
public int motion = 5;
private void InitializeTimers()
{
this.oneSecondTimer = new System.Timers.Timer(1000);
this.oneSecondTimer.Elapsed += new System.Timers.ElapsedEventHandler(oneSecondTimer_elapsed);
}
public void start_one_second_timer()
{
run_time = 0;
oneSecondTimer.Enabled = true;
}
public void stop_one_second_timer()
{
oneSecondTimer.Enabled = false;
run_time = 0;
}
Random mot = new Random();
private void oneSecondTimer_elapsed(object source, System.Timers.ElapsedEventArgs e)
{
run_time++;
motion = mot.Next(1, 10);
this.oneSecondThread = new Thread(new ThreadStart(this.UpdateTextFields));
this.oneSecondThread.Start();
}
private void UpdateTextFields()
{
this.motionDisplay.Text = this.motion.ToString();
}
motionDisplay is just a textbox in my main form. I get the Invalid Operation Exception pointing me towards the help on how to make Thread-Safe calls. I also tried backgroundworker and end up with the same result. The details are that motionDisplay is accessed from a thread other than the thread it was created on.
So looking for some suggestions as to where my mistakes are.
Best Regards. I continue to iterate on this and will update if I find a solution.
Use a System.Forms.Timer rather than a System.Timers.Timer. It will fire it's elapsed event in the UI thread.
Don't create a new thread to update the UI; just do the update in the elapsed event handler.
Try this
private void UpdateTextFields()
{
this.BeginInvoke(new EventHandler((s,e)=>{
this.motionDisplay.Text = this.motion.ToString();
}));
}
This will properly marshall a call back to the main thread.
The thing with WinForm development is that all the controls are not thread safe. Even getting a property such as .Text from another thread can cause these type of errors to happen. To make it even more frustrating is that sometimes it will work at runtime and you won't get an exception, other times you will.
This is how I do it:
private delegate void UpdateMotionDisplayCallback(string text);
private void UpdateMotionDisplay(string text) {
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.motionDisplay.InvokeRequired) {
UpdateMotionDisplayCallback d = new UpdateMotionDisplayCallback(UpdateMotionDisplay);
this.Invoke(d, new object[] { text });
} else {
this.motionDisplay.Text = text;
}
}
When you want to update the text in motionDisplay just call:
UpdateMotionDisplay(this.motion.ToString())
I want to run multiple threads at a time simultaneously (max 5 threads, for example) and when either one finishes, the new one starts with different data. (one finishes, one new start, two finishes, two new start...)
Main for loop is in main form, but run from a different thread not to block the UI.
When I run it, program adds 5 web browser controls (as a visual progress) and when the page is done loading it removes loaded ones.
The problem is no more controls is being added to the form.
Maybe semaphore is not released properly to allow new ones to start or am I missing something else?
And if I close the program, it doesn't exit, I think it gets blocked on WaitHandle.WaitOne because there are still more jobs to be done.
I removed some non needed data for more code clarity.
Semaphore pool = new Semaphore(5, 5);
Scraper[] scraper = new Scraper[5];
Gecko.GeckoWebBrowser wb = null;
int j = 0;
for (int i = 0; i < arrScrapeboxItems.Count; i++)
{
pool.WaitOne();
bool pustiMe = true;
while (pustiMe)
{
if (scraper[j] == null) scraper[j] = new Scraper();
if (scraper[j].tred == null)
{
ScrapeBoxItems sbi = (ScrapeBoxItems)arrScrapeboxItems[i];
doneEvents.Add(new ManualResetEvent(false)); // this is for WaitHandle.WaitAll after the for loop is done all the items
wb = new Gecko.GeckoWebBrowser();
PoolObjects po = new PoolObjects();
po.link = sbi.link;
// etc...
scraper[j].ThreadsCompleted += new Scraper.ThreadsHandler(frmMain_NextThreadItemsCompleted);
scraper[j].tred = new Thread(new ParameterizedThreadStart(scraper[j].Scrape));
scraper[j].tred.Start(po);
pustiMe = false;
if (j == maxThreads - 1)
j = 0;
else
j++;
break;
}
else if (scraper[j].tred.IsAlive) // if the thread is finished, make room for new thread
{
scraper[j] = null;
}
if (pustiMe) Thread.Sleep(1000);
}
}
// event from Scraper class
void frmMain_ThreadsCompleted()
{
pool.Release();
}
And the Scraper class look like:
public void Scrape(object o)
{
po = (PoolObjects)o;
// do stuff with po
po.form.Invoke((MethodInvoker)delegate
{
po.form.Controls.Add(po.wb);
po.wb.DocumentCompleted += new EventHandler<Gecko.Events.GeckoDocumentCompletedEventArgs>(wb_DocumentCompleted);
po.wb.Navigate(po.link);
});
}
void wb_DocumentCompleted(object sender, Gecko.Events.GeckoDocumentCompletedEventArgs e)
{
var br = sender as Gecko.GeckoWebBrowser;
if (br.Url == e.Uri)
{
form.Controls.Remove(po.wb);
ThreadsCompleted();
manualReset.Set();
}
}
Either you have a typo or a huge bug. You have
else if (scraper[j].tred.IsAlive)
{
scraper[j] = null;
}
I think you want if (!scraper[j].tred.IsAlive). Otherwise, you'll end up overwriting an active Scraper reference in the array.
More to the point, trying to maintain that array of Scraper objects is causing you a lot of complication that you really don't need. You already have the semaphore controlling how many concurrent threads you can have, so the array of Scraper objects is unnecessary noise.
Also, you don't want a whole bunch of ManualResetEvent objects to wait on. WaitAll can't wait on more than 63 items, so if you have more than that in your items list, WaitAll isn't going to do it for you. I show below a better way to make sure all the jobs are completed.
for (int i = 0; i < arrScrapeboxItems.Count; i++)
{
pool.WaitOne();
ScrapeBoxItems sbi = (ScrapeBoxItems)arrScrapeboxItems[i];
wb = new Gecko.GeckoWebBrowser();
PoolObjects po = new PoolObjects();
po.link = sbi.link;
// more initialization of po ...
// and then start the thread
Thread t = new Thread(ScrapeThreadProc);
t.Start(po);
}
// Here's how you wait for all of the threads to complete.
// You have your main thread (which is running here) call `WaitOne` on the semaphore 5 times:
for (int i = 0; i < 5; ++i)
{
pool.WaitOne();
}
private void ScrapeThreadProc(object o)
{
var po = (PoolObjects)o;
Scraper scraper = new Scraper();
// initialize your Scraper object
scraper.ThreadsCompleted += new Scraper.ThreadsHandler(frmMain_NextThreadItemsCompleted);
scraper.Scrape(po);
// scraping is done. Dispose of the scraper and the po.
// and then release the semaphore
pool.Release();
}
That should greatly simplify your code.
The idea behind having the main thread wait on the semaphore 5 times is pretty simple. If the main thread can acquire the semaphore 5 times without calling Release, then you know that there aren't any other jobs running.
There are other ways to do this, as well, but they would require some more involved restructuring of your code. You should look into the Task Parallel Library, specifically Parallel.ForEach, which will handle the threading for you. You can set the maximum number of concurrent threads to 5, so that you won't get too many threads going at once.
You could also do this using a producer/consumer setup with BlockingCollection or some other shared queue.
In both of those scenarios, you end up creating 5 persistent threads that cooperatively process items from the list. That is typically more efficient than creating one thread for each item.
I have a c# application that uses a background worker thread, and quite successfully updates the UI from the running thread. The application involves shortest path routing on a network, and I display the network and the shortest path, on the UI, as the background worker proceeds. I would like to allow the user to slow down the display through use of a slider, while the application is running.
I found this as a suggestion, but it is in vb.net, I am not clear on how to get it to work in c#.
How can the BackgroundWorker get values from the UI thread while it is running?
I can pass the value of the slider to the backgroundworker as follows:
// Start the asynchronous operation.
delay = this.trackBar1.Value;
backgroundWorker1.RunWorkerAsync(delay);
and use it within the backgroundworker thread, but it only uses the initially-sent value. I am not clear on how to pick up the value from inside the backgroundworker when I move the slider on the UI.
I have previously used multiple threads and delegates, but if it is possible to utilize the background worker, I would prefer it for its simplicity.
5/10/2012
Thanks to all for your responses. I am still having problems, most likely because of how I have structured things. The heavy duty calculations for network routing are done in the TransportationDelayModel class. BackgroundWorker_DoWork creates an instance of this class, and then kicks it off. The delay is handled in TransportationDelayModel.
The skeleton of code is as follows:
In UI:
private void runToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (sqliteFileName.Equals("Not Set"))
{
MessageBox.Show("Database Name Not Set");
this.chooseDatabaseToolStripMenuItem_Click(sender, e);
}
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
delay = this.trackBar1.Value;
// pass the initial value of delay
backgroundWorker1.RunWorkerAsync(delay);
// preclude multiple runs
runToolStripMenuItem1.Enabled = false;
toolStripButton2.Enabled = false;
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (!backgroundWorkerLaunched)
{
// instantiate the object that does all the heavy work
TransportationDelayModel TDM = new TransportationDelayModel(worker, e);
// kick it off
TDM.Run(sqliteFileName, worker, e);
backgroundWorkerLaunched = true;
}
}
The TransportationDelayModel constructor is:
public TransportationDelayModel(BackgroundWorker worker, DoWorkEventArgs e)
{
listCentroids = new List<RoadNode>();
listCentroidIDs = new List<int>();
listNodes = new List<RoadNode>();
listNodeIDs = new List<int>();
listRoadLink = new List<RoadLink>();
roadGraph = new AdjacencyGraph<int, RoadLink>(true); // note parallel edges allowed
tdmWorker = worker;
tdmEvent = e;
networkForm = new NetworkForm();
}
so I have the tdmWorker, which allows me to pass information back to the UI.
In the internal calculations in TransportationDelayModel, I sleep for the delay period
if (delay2 > 0)
{
tdmWorker.ReportProgress(-12, zzz);
System.Threading.Thread.Sleep(delay2);
}
so the problem seems to be how to pass an updated slider value from the UI back to the object that is executing in the background worker. I have tried a number of combinations, sort of thrashing around, to no avail, either nothing happens or I get a message about not being allowed to access what is happening on the other thread. I realize that if I were doing all the work in the DoWork event handler, then I should be able to do things as you suggest, but there is too much complexity for that to happen.
Again, thank you for your suggestions and help.
6/2/2012
I have resolved this problem by two methods, but I have some questions. Per my comment to R. Harvey, I have built a simple application. It consists of a form with a run button, a slider, and a rich text box. The run button launches a background worker thread that instantiates an object of class "Model" that does all the work (a simplified surrogate for my TransportationModel). The Model class simply writes 100 lines to the text box, incrementing the number of dots in each line by 1, with a delay between each line based on the setting of the slider, and the slider value at the end of the line, something like this:
....................58
.....................58
......................58
.......................51
........................44
.........................44
The objective of this exercise is to be able to move the slider on the form while the "Model" is running, and get the delay to change (as in above).
My first solution involves the creation of a Globals class, to hold the value of the slider:
class Globals
{
public static int globalDelay;
}
then, in the form, I update this value whenever the trackbar is scrolled:
private void trackBar1_Scroll(object sender, EventArgs e)
{
Globals.globalDelay = this.trackBar1.Value;
}
and in the Model, I just pick up the value of the global:
public void Run(BackgroundWorker worker, DoWorkEventArgs e)
{
for (int i = 1; i < 100; i++)
{
delay = Globals.globalDelay; // revise delay based on static global set on UI
System.Threading.Thread.Sleep(delay);
worker.ReportProgress(i);
string reportString = ".";
for (int k = 0; k < i; k++)
{
reportString += ".";
}
reportString += delay.ToString();
worker.ReportProgress(-1, reportString);
}
}
}
This works just fine.
My question: are there any drawbacks to this approach, which seems very simple to implement and quite general.
The second approach, based on suggestions by R. Harvey, makes use of delegates and invoke.
I create a class for delegates:
public class MyDelegates
{
public delegate int DelegateCheckTrackBarValue(); // create the delegate here
}
in the form, I create:
public int CheckTrackBarValue()
{
return this.trackBar1.Value;
}
and the Model class now has a member m_CheckTrackBarValue
public class Model
{
#region Members
Form1 passedForm;
public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;
#endregion Members
#region Constructor
public Model(BackgroundWorker worker, DoWorkEventArgs e, Form1 form)
{
passedForm = form;
}
When the background thread is launched by the run button, the calling form is passed
private void button1_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (!backgroundWorkerLaunched)
{
// instantiate the object that does all the heavy work
Model myModel= new Model(worker, e, this);
Model.m_CheckTrackBarValue = new MyDelegates.DelegateCheckTrackBarValue(this.CheckTrackBarValue);
// kick it off
myModel.Run(worker, e);
backgroundWorkerLaunched = true;
}
}
Finally, in the Model, the Invoke method is called on the passed form to get the value of the trackbar.
public void Run(BackgroundWorker worker, DoWorkEventArgs e)
{
for (int i = 1; i < 100; i++)
{
int delay = (int)passedForm.Invoke(m_CheckTrackBarValue,null); // invoke the method, note need the cast here
System.Threading.Thread.Sleep(delay);
worker.ReportProgress(i);
string reportString = ".";
for (int k = 0; k < i; k++)
{
reportString += ".";
}
reportString += delay.ToString();
worker.ReportProgress(-1, reportString);
}
}
This works as well. I kept getting an error until I made the member variable static, e.g.
public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;
My questions on this solution: Are there advantages to this solution as regards to the previous version? Am I making things too complicated in the way I have implemented this? Why does m_CheckTrackBarValue need to be static.
I apologize for the length of this edit, but I thought that the problem and solutions might be of interest to others.
You have to pass the TrackBar object to the BackgroundWorker, not delay. delay doesn't change once you set it.
To simplify the needed Invoke(), you can use a helper method, such as this one:
Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);
I will assume that you are already familiarized with cross-thread invocation to update the UI. So, the solution is very simple: in your worker thread, after each iteration, invoke the UI to get the slider thumb position.
To use a backgroundworker, you add a method to the DoWork property, like this:
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
In the DoWork method, you need to check the variable where the updated delay is set.
This could be an integer field that is available on the containing Form or UI control, or it could be the TrackBar itself.
I'm using WatiN to parse my web site. I have a button that starts the process. I open a browser window and navigate where I need to go, then I create a new task that calls a method called DoWork.
My problem is that if I call a new method at the end of DoWork to do something else I get strange results when I try to have the program navigate my website, however, if I don't call this new method from DoWork and just hook the new method up to a button click all works fine. So my question is am I not properly calling my new method from the background process method, Dowork?
Code:
IE browser = new IE("http://www.mywebsite.com/");
string startYear;
string endYear;
int NumRows;
Task myThread;
public Form1()
{
InitializeComponent();
}
private void Start_Click(object sender, EventArgs e)
{
startYear = txtStartYear.Text;
endYear = txtEndYear.Text;
//website navigation work removed for brevity
browser.Button(Find.ById("ContentPlaceHolder1_btnApplyFilter")).Click();
int numRows = browser.Div(Find.ById("scroller1")).Table(Find.First()).TableRows.Count -1;
NumRows = numRows;
lblTotalRows.Text = numRows.ToString();
myThread = Task.Factory.StartNew(() => DoWork());
}
public void DoWork()
{
List<string> myList = new List<string>(NumRows);
txtStartYear.Text = startYear;
txtEndYear.Text = endYear;
for (int i = 1; i < NumRows; i++)
{
TableRow newTable = browser.Div(Find.ById("scroller1")).Table(Find.First()).TableRows[i];
string coll = string.Format("{0},{1},{2},{3},{4}", newTable.TableCells[0].Text, newTable.TableCells[1].Text, newTable.TableCells[2].Text, newTable.TableCells[3].Text, newTable.TableCells[4].Text);
myList.Add(coll);
label1.Invoke((MethodInvoker)delegate
{
label1.Text = i.ToString();
});
}
//database work removed for brevity.
browser.Button(Find.ById("btnFilter")).Click();
newMethod();
}
public void newMethod()
{
int start = int.Parse(startYear);
start++;
startYear = start.ToString();
int end = int.Parse(endYear);
end++;
endYear = end.ToString();
browser.SelectList(Find.ById("selStartYear")).SelectByValue(startYear);
browser.SelectList(Find.ById("selEndYear")).SelectByValue(endYear);
//removed for brevity
}
}
To reiterate, if I call newMethod from Dowork the line browser.SelectList(Find.ById("selStartYear")).SelectByValue(startYear) doesn't behave properly, but if I remove the call to newMethod from Dowork and just hook newMethod up to a button it works fine. I'm wondering if it has to do with DoWork being a background task?
When I say it doesn't behave properly I mean that when you select an item from the drop down list the page auto posts back, however the above line of code selects it but the page doesn't post back, which shouldn't be possible. If I don't call the method within DoWork I don't have this issue.
You're modifying a UI element from a non-UI thread. You've already got code which deals with that within DoWork, via Control.Invoke - you need to do the same kind of thing for newMethod. It would probably be easiest just to invoke the whole method in the UI thread:
// At the end of DoWork
Action action = newMethod;
label.BeginInvoke(action);
(I'm using label.BeginInvoke as I'm not sure whether the browser itself is a "normal" control - but using label will get to the right thread anyway. If browser.BeginInvoke compiles, that would be clearer.)
I suspect it's a problem with the select list control. When I browse websites, I sometimes select drop down items by keyboard. Sometimes, it just doesn't postback, while using mouse always guarantee a postback.
I think you might be better off putting an extra button and do a browser.Button(Find.ById("btnFilter")).Click(); kind of thing to invoke a postback.
If the functions in the browser doesn't perform the proper cross thread checking, what Jon Skeet said should help.