I'm making a C# app to monitor some stuff in SQL. I use a background worker to pick up SQL data then build some charts based on the data. Pretty basic. However there's one frustrating thing about this. Using Thread.Sleep in the worker completely locks up the UI. No loading gif, inputs don't register, nada. This is very odd behavior to me because from what I read about the background worker use cases, it should run on it's own thread, COMPLETELY separate from the UI. So what gives? What can I use in place of this? Here's my background worker code:
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (CollectionCanceled)
return;
//Get data from SQL DB
var jobService = _serviceFactory.CreateJobService();
var jobs = jobService.GetAllJobs(true);
backgroundWorker1.ReportProgress(0, jobs);
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var allJobs = e.UserState as IList<Job>;
if (allJobs == null || CollectionCanceled)
return;
//Build collection
Dictionary<string, Dictionary<string, int>> details = new Dictionary<string, Dictionary<string, int>>();
foreach (var job in allJobs)
{
var overViewKey = job.State.ToString();
var detailKey = string.Format("{0} ({1})", job.Name, job.Type);
if (!details.ContainsKey(overViewKey))
details.Add(overViewKey, new Dictionary<string, int>());
if (!details[overViewKey].ContainsKey(detailKey))
details[overViewKey].Add(detailKey, 0);
details[overViewKey][detailKey]++;
}
//Build charts
Overview.Series.Clear();
Detailed.Series.Clear();
Overview.Series.Add("Jobs");
Detailed.Series.Add("Jobs");
foreach (var runniningOrEnqueued in details)
{
Overview.Series["Jobs"].Points.AddXY(runniningOrEnqueued.Key, runniningOrEnqueued.Value.Count);
foreach (var jobDetail in runniningOrEnqueued.Value)
Detailed.Series["Jobs"].Points.AddXY(jobDetail.Key, jobDetail.Value);
}
//Stop for however many secs the user specified
Thread.Sleep((int)TimeSpan.FromSeconds(WaitTimer).TotalMilliseconds);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!CollectionCanceled)
{
ExecuteBackGroundWork();
}
else
{
CollectionCanceled = false;
}
}
private void ExecuteBackGroundWork()
{
backgroundWorker1.RunWorkerAsync();
}
BackgroundWorker_ProgressChanged
does not happen on the worker thread, it happens on the UI thread. Only code that happens inside BackgroundWorker_DoWork
is run on the worker thread.
Most of the work you are doing inside ProgressChanged (if not all, I don't see any explicit UI interaction in your code unless Overview
and Detailed
are UI componets) should be happening inside DoWork.