I'm stuck trying to do something that seems like it should be easier than I'm making it.
I would like to update a status label (I.E. progress) on the GUI of the program from some worker threads.
I can't use a synchronous invoke call because the main thread is blocked on thread.Join(); to re-enable interface input/cleanup threads. This causes freezing in the program.
I do not want to use an asynchronous BeginInvoke because then it waits until the program is finished to update the progress...defeating the purpose.
tl;dr - I know WHY it won't work, but I'm not sure how to fix it.
Button_Search_Click(object sender, EventArgs e)()
{
DisableInput(); //Block input on start of function
Cursor.Current = Cursors.WaitCursor; //set wait cursor
//read combobox input
string objectType = comboBox_Object.SelectedItem.ToString();
string conditionType = comboBox_ConditionType.SelectedItem.ToString();
string conditionOperator = comboBox_equals.SelectedItem.ToString();
//create a list of worker threads
List<Thread> workerThreads = new List<Thread>();
//for each line in the textbox
foreach (string searchText in textBox_SearchText.Lines)
{
if (String.IsNullOrWhiteSpace(searchText)) continue;
//foreach line in a listbox
foreach (String uri in Get_selected_sites())
{
string cred = (creddict[uri]);
Thread thread = new Thread(() => Search(uri, cred, objectType, conditionType, conditionOperator, searchText));
workerThreads.Add(thread);
thread.Start(); //start main "work" function
}
// Wait for all the threads to finish
foreach (Thread thread in workerThreads)
{
thread.Join();
}
}
Displaydata();
EnableInput(); //unlock input
Cursor.Current = Cursors.Default; //set normal cursor
}
Search(uri, cred, objectType, conditionType, conditionOperator, searchText)
{
DoStuff();
//Update toolStripStatusLabel with progress stored in global int variable
//This doesn't work well because it waits until Thread.join() to update status label.
//BeginInvoke(new Action(() => Results_Count.Text = "Total Results = " + totalResults));
//This doesn't work at all because the main thread is blocked on Thread.Join() -- it freezes the program
//statusStrip1.Invoke(new Action(() => Results_Count.Text = "Total Results = " + totalResults));
//This doesn't work/errors/crashes because the GUI is being modified by a thread other than main
//Results_Count.Text = "Total Results = " + totalResults;
DoMoreStuff();
}
Thank you very much for any tips you can provide!
Fix your method so it looks more like this:
async void Button_Search_Click(object sender, EventArgs e)()
{
DisableInput(); //Block input on start of function
Cursor.Current = Cursors.WaitCursor; //set wait cursor
//read combobox input
string objectType = comboBox_Object.SelectedItem.ToString();
string conditionType = comboBox_ConditionType.SelectedItem.ToString();
string conditionOperator = comboBox_equals.SelectedItem.ToString();
//create a list of worker threads
List<Task> workerTasks = new List<Task>();
//for each line in the textbox
foreach (string searchText in textBox_SearchText.Lines)
{
if (String.IsNullOrWhiteSpace(searchText)) continue;
//foreach line in a listbox
foreach (String uri in Get_selected_sites())
{
string cred = (creddict[uri]);
workerTasks.Add(Task.Run(() => Search(uri, cred, objectType, conditionType, conditionOperator, searchText)));
}
await Task.WhenAll(workerTasks);
}
Displaydata();
EnableInput(); //unlock input
Cursor.Current = Cursors.Default; //set normal cursor
}
That way, the Button_Search_Click()
won't block the UI thread while the tasks are running, and you can use normal Invoke()
or whatever mechanism you like to post updates to the UI thread.