简体   繁体   中英

How can I call a method in the background without “The function evaluation requires all threads to run”

So I have this Windows Form Application of a restaurant where I have a module of table Selection and it's going to be used by at least 4 waiters.

It makes sense that I need to Sync the software when a Table is Set Occupied. My method, called RefreshApp , works like a charm, at least for my needs. The problem reside in that it can only be successfully called here:

  private void loadTables() { // Some load tables code... RefreshApp(); } 

Put the method in here and it will run perfectly, just 1 time... thats my problem, I need to refresh it every once in a while, so I tried in a BackGroundWorker:

  private void bgWorker_DoWork(object sender, DoWorkEventArgs e) { while (true) { Thread.Sleep(100); if (_stopwatch.Elapsed >= TimeSpan.FromSeconds(Constants.refreshTime) && Constants.alreadyWorking == false) { Constants.alreadyWorking = true; RefreshApp(); // Restart the stopwatch for next sync event _stopwatch.Restart(); } } 

But if I run the code there I get “The function evaluation requires all threads to run”, and if I use the code in a Button_click method to test it in the form manually it give me the same error.

 private void btn_Refresh_Click(object sender, EventArgs e) { RefreshApp(); } 

So my Question is, How can I call RefreshApp method in a certain amount of time in background without this kind of error?

Here is the code for reference (bear in mind that this method already work as needed):

 private void RefreshApp() { SqlDataReader reader = sqlCommandGetTables.ExecuteReader(); // foreach PictureBox representation of a table, get db value, compare, assign table state foreach (PictureBox item in from d in group_Layout.Controls.OfType<PictureBox>().Reverse() select d) { if (item.Name == "DMPS_Layout") continue; reader.Read(); //if the item.Text property equals database value [mesa1], assign image if (item.Text == reader.GetSqlValue(1).ToString() && Int32.Parse(reader.GetValue(0).ToString()) == Constants.numMesaEmpty) item.Image = Properties.Resources.mesaEmpty; if (item.Text == reader.GetSqlValue(1).ToString() && Int32.Parse(reader.GetValue(0).ToString()) == Constants.numMesaBusy) item.Image = Properties.Resources.mesaBusy; if (item.Text == reader.GetSqlValue(1).ToString() && Int32.Parse(reader.GetValue(0).ToString()) == Constants.numMesaUnavailable) item.Image = Properties.Resources.mesaUnavailable; } } 

I don't understand the error, but you should not access WinForms Controls from different thread than the main (pumping messages). You can use Timer (event will be called in main thread after getting WM_TIMER message).

You simply cannot call RefreshApp from BackgroundWorker (on any thread except the main).

NOTE: I was refering to System.Windows.Forms.Timer (not System.Threading.Timer )
NOTE2: Using Control.Invoke() (InvokeRequired, BeginInvoke, EndInvoke) is another option but Timer was ideal when I saw the code with StopWatch.

This is not technically a case of concurrency , because you just moved the code from the main thread to another. To make it work, you should invoke the RefreshApp method on the main thread:

this.Invoke(RefreshApp);  // `this` being your Form

I think the error you get is irrelevant here, but if you want that fixed too: did you place a condition on one of your beakpoints? That's the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM