I found a few other articles regarding using background worker which I've linked just below. I used the code examples and attempted to do this to run 3 different SQL Query's. In the code posted below when I break inside of RunBackGroundWorkerProcesses1 it does stop there and is called but method for worker_DoWork1 is never called even though it is in the code. I'm assuming that I've misunderstood this, can someone add some clarity.
Link I used for reference:
WPF Multithreading
Code:
public CallInformationMainScreen()
{
InitializeComponent();
//This is where i call the background processes
RunBackGroundWorkerProcesses1();
RunBackGroundWorkerProcesses2();
RunBackGroundWorkerProcesses3();
}
#endregion
#region Methods used to generate data for the UI
public string DisplayTotalDailyCalls()
{
DailyCallsQuery db = new DailyCallsQuery();
return db.GetNumber(SkillNumber);
}
public string DisplayTotalLastSevenCalls()
{
PrevSevenCallQuery db = new PrevSevenCallQuery();
return db.GetNumber(SkillNumber);
}
public string DisplayDailyAbandonCalls()
{
DailyAbandonQuery db = new DailyAbandonQuery();
return db.GetNumber(SkillNumber);
}
#endregion
#region Background worker processes
private void RunBackGroundWorkerProcesses1()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork1);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void RunBackGroundWorkerProcesses2()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork2);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void RunBackGroundWorkerProcesses3()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork3);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void worker_DoWork1(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyCalls = DisplayTotalDailyCalls();
e.Result = TotalDailyCalls;
}
private void worker_DoWork2(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyLast7Days = DisplayTotalLastSevenCalls();
e.Result = TotalDailyCalls;
}
private void worker_DoWork3(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyAbandon = DisplayDailyAbandonCalls();
e.Result = TotalDailyAbandon;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
// handle the System.Exception
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// now handle the case where the operation was cancelled...
ErrorHolder = "The operation was cancelled";
}
else
{
// Finally, handle the case where the operation succeeded
ErrorHolder = e.Result.ToString();
}
}
#endregion
You don't start your timers. See Timer.Start Method ().
private void RunBackGroundWorkerProcesses1()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork1);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
t.Start(); // Start the timer
}
I'm posting this to demonstrate an easier way to do this. It's not meant to be a direct answer to the question.
If you NuGet "System.Reactive" and the associated WPF libraries you can do this:
IDisposable subscription =
new []
{
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayTotalDailyCalls()),
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayTotalLastSevenCalls()),
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayDailyAbandonCalls()),
}
.Merge()
.ObserveOnDispatcher()
.Subscribe(x => ErrorHolder = x, e => MessageBox.Show(e.Error.Message));
That's it. Job done. All of your code in techically one line of code.
BackgroundWorker.RunWorkerAsync() is only called when the Timer.Elapsed event is fired. Since the timer is set to 10 second intervals, the BackgroundWorker won't start for 10 seconds. You probably should call BackgroundWorker.RunWorkerAsync() after creating and initializing it so that it will start right away.
Related
I'm trying to run a function after a thread has completed running. My thread starts when an UI button is pressed and the thread takes a while to complete.
Once it's done running I want to call a function. Here is the code I tried so far. When I try to run my code the thread never executes and the application freezes. Any suggestion on how to fix this would be helpful.
public bool StartProbe()
{
if (File.Exists(Path.Combine(ObsProbeFolder, "probePJM.exe")))
{
ThreadStart ProbeThreadStart = new ThreadStart(() =>
// right side of lambda
{
// does stuff
});
ProbeThread = new Thread(ProbeThreadStart);
ProbeThread.Priority = ThreadPriority.BelowNormal;
ProbeThread.SetApartmentState(ApartmentState.STA);
ProbeThread.Start();
}
else
{
return false;
}
// waiting for thread to finish
ProbeThread.Join();
// run a function
loadData();
return true;
}
I would use a BackgroundWorker:
Worker = new BackgroundWorker();
Worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
Worker.DoWork += Worker_DoWork;
Worker.RunWorkerAsync(new BackgroundArguments()
{
// arguments
});
Work on alternate thread:
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// do stuff
}
Return to UI thread:
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// load data or whatever on UI thread
}
I want to display a "loading form" (a form with some text message plus a progressBar with style set to marquee) while the BackgroundWorker's job isn't done. When the BackgroundWorker is done, the loading form must be closed automatically. Although I do use a BackgroundWorker, the main thread should wait until it's done. I was able to do that using a AutoResetEvent but I noticied that as it does block the main thread, the form loading's progressBar is freezed too.
My question is: How can I show that form without freeze it while runing a process in background and wait for it finish? I hope it's clear.
Here's my current code:
BackgroundWorker bw = new BackgroundWorker();
AutoResetEvent resetEvent = new AutoResetEvent(false);
//a windows form with a progressBar and a label
loadingOperation loadingForm = new loadingOperation(statusMsg);
//that form has a progressBar that's freezed. I want to make
// it not freezed.
loadingForm.Show();
bw.DoWork += (sender, e) =>
{
try
{
if (!e.Cancel)
{
//do something
}
}
finally
{
resetEvent.Set();
}
};
bw.RunWorkerAsync();
resetEvent.WaitOne();
loadingForm.Close();
MessageBox.Show("we are done!");
Connect your BackgroundWorker's RunWorkerCompleted to a callback that will close the form like so:
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
loadingForm.Close();
MessageBox.Show("we are done!");
}
You can delete the resetEvent.WaitOne();
You'll need to make loadingForm a field of course.
Tell me more
Occurs when the background operation has completed, has been canceled, or has raised an exception
BackgroundWorker.RunWorkerCompleted
Make the login form object an instance variable.
//use RunWorkerCompleted event to get notified about work completion where you close the form.
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
event handler code:
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.loadingForm.close();
}
Reference: https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.runworkercompleted(v=vs.110).aspx
Cek this script, Loading is Form with PictureBox - image gif
private delegate void showProgressCallBack(int value);
private void btnStart5_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
Loading f = new Loading();
f.Show();
bw.DoWork += (s, ea) =>
{
try
{
test1();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
};
bw.RunWorkerCompleted += (s, ea) =>
{
f.Close();
};
bw.RunWorkerAsync();
}
private void showProgress(int value)
{
if (progressBar1.InvokeRequired)
{
showProgressCallBack showProgressDelegate = new showProgressCallBack(showProgress);
this.Invoke(showProgressDelegate, new object[] {value});
}
else
{
progressBar1.Value = value;
}
}
private void test()
{
showProgress(20);
Thread.Sleep(3000);
showProgress(80);
Thread.Sleep(2000);
showProgress(100);
}
I found a few examples on the internet but I'm having a hard time trying to run my async call inside a background worker. I'm working in WP8. What's missing?
Edit: The purpose of this is to update the values I'm reading from time to time. Let's say 1s.
Here is my async code, it just gets and stores some data in providers []:
public void getAllProvidersMethod()
{
try
{
sc.getAllProvidersCompleted += new EventHandler<ServiceReference1.getAllProvidersCompletedEventArgs>(callback);
sc.getAllProvidersAsync();
}
catch (System.Exception e)
{
MessageBox.Show(e.ToString());
}
}
public void callback(object sender, ServiceReference1.getAllProvidersCompletedEventArgs e)
{
try
{
providers = new String[e.Result.Length];
for (int i = 0; i < e.Result.Length; i++)
{
providers[i] = e.Result[i].ToString();
}
}
catch (System.Exception d)
{
MessageBox.Show(d.ToString());
}
}
This is my background worker:
private void networkWorker()
{
var obj = App.Current as App;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
getAllProvidersMethod();
});
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
MessageBox.Show(" ");
});
bw.RunWorkerAsync();
}
Ok I managed to get it working!
For anyone that wants to run some async code automatically from time to time, forget about backgroundworkers, what you are looking for is a Timer.
Thank you Servy for the Timer hint.
Let's say I want to call asyncCall for each 5 seconds.
It's very simple. First define how long is your wait time between calls (how long you want it to wait before calling the same code again).
System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 5000); // HERE - for example 5000 is 5 seconds
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
And then all you need is to write the code you want to repeat inside this method:
void dt_Tick(object sender, EventArgs e)
{
asyncCall();
}
In this case for each 5 seconds it will call asyncCall.
I have some problem with backgroundWorker class. I wish I could within one function cancel Backroundworker and just after it start Backgroundworker dowork from scratch. It cause race and I have no idea how to change it. Is there any alternative to Backgroundworker in .net 3.5
Edited:
My code:
BackgroundWorker worker = new BackgroundWorker();
public void Func()
{
if(worker.IsBusy)
{
worker.CancelAsync();
worker = new BackgroundWorker();
}
View.Clear();
worker.WorkerSupportsCancellation = true;
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
BackgroundWorker sender = s as BackgroundWorker;
if(sender.CancellationPending)
{
args.Cancel = true;
return;
}
View.Generate(Filter);
};
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
if(args.Error != null)
{
MessageBox.Show(args.Error.Message);
return;
}
BackgroundWorker sender = s as BackgroundWorker;
if(args.Cancelled )
{
View.Clear();
}
};
worker.RunWorkerAsync();
}
The problem is: cancelAsync doesnt close worker at all and my view is generated in incorrect way
You can use CancelAsync() and set WorkerSupportsCancellation to true and implements a loop to get CancellationPending
while(x.CancellationPending) { /*TODO*/ }
consider this code block
public void ManageInstalledComponentsUpdate()
{
IUpdateView view = new UpdaterForm();
BackgroundWorker worker = new BackgroundWorker();
Update update = new Update();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(update.DoUpdate);
worker.ProgressChanged += new ProgressChangedEventHandler(view.ProgressCallback);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(view.CompletionCallback);
worker.RunWorkerAsync();
Application.Run(view as UpdaterForm);
}
It all works great but I want to understand why the objects (worker,view and update) don't get garbage collected
Threads count as root objects; I don't know exactly how BackgroundWorker operates, but it seems likely that the primary thread method is going to access state on the worker instance; as such, the worker thread itself will keep the BackgroundWorker instance alive until (at least) the thread has exited.
Of course; collection also requires that all other (live) objects have de-referenced the worker object; note also that collection of stack variables can be different in debug/release, and with/without a debugger attached.
[edit]
As has also been noted; the event handlers on the worker (in your code) will keep the "view" and "update" objects alive (via the delegate), but not the other way around. As long as the worker has a shorter life than the "view" and "update", you don't need to get paranoid about unsubscribing the events. I've edited the code to include a "SomeTarget" object that isonly referenced by the worker: you should see this effect (i.e. the target dies with the worker).
Re worker getting collected when the thread dies: here's the proof; you should see "worker finalized" after the worker reports exit:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Demo : Form
{
class ChattyWorker : BackgroundWorker
{
~ChattyWorker()
{
Console.WriteLine("Worker finalized");
}
}
class SomeTarget
{
~SomeTarget()
{
Console.WriteLine("Target finalized");
}
public SomeTarget()
{
Console.WriteLine("Target created");
}
public void Foo(object sender, EventArgs args)
{
Console.WriteLine("Foo");
}
}
static void Collect(object sender, EventArgs args)
{
Console.WriteLine("Collecting...");
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Tick += Collect;
timer.Start();
ChattyWorker worker = new ChattyWorker();
worker.RunWorkerCompleted += new SomeTarget().Foo;
worker.DoWork += delegate
{
Console.WriteLine("Worker starting");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(250);
Console.WriteLine(i);
}
Console.WriteLine("Worker exiting");
};
worker.RunWorkerAsync();
}
[STAThread]
static void Main()
{ // using a form to force a sync context
Application.Run(new Demo());
}
}
Event handlers are references, so until you have event handler attached to the worker, it would not be considered "unreachable".
In your ComplitionCallback take care to unhook the event handlers.
Those local variable objects are keep alive until the function exits, which is when the form exits. So null them out before call to Run, or move them to a different context.
public void ManageInstalledComponentsUpdate() {
UpdaterForm form = new UpdaterForm();
FireAndForgetWorker( form );
Application.Run( form ); //does not return until form exits
}
void FireAndForgetWorker( IUpdateView view ) {
BackgroundWorker worker = new BackgroundWorker();
Update update = new Update();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(update.DoUpdate);
worker.ProgressChanged += new ProgressChangedEventHandler(view.ProgressCallback);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(view.CompletionCallback);
worker.RunWorkerAsync();
}
A note to vsick:
Try running the following program, you will be surprised that x lives forever.
using System;
class FailsOnGarbageCollection
{ ~FailsOnGarbageCollection() { throw new NotSupportedException(); } }
class Program{
static void WaitForever() { while (true) { var o = new object(); } }
static void Main(string[] args)
{
var x = new FailsOnGarbageCollection();
//x = null; //use this line to release x and cause the above exception
WaitForever();
}
}