I have a button click event for continue:
private void button3_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
button2.Enabled = true;
button3.Enabled = false;
}
else
{
backgroundWorker1.RunWorkerAsync();
button2.Enabled = true;
button3.Enabled = false;
}
}
And a button click event for pausing:
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
button3.Enabled = true;
soundPlay = false;
stop_alarm = true;
}
}
The problem is with the button3 click event the continue code sometimes the background is busy so i can enable false/true the buttons but the backgroundworker is keep working.
I want to pause the DoWork event and to continue.
This is my DoWork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (tempCpuValue >= (float?)numericUpDown1.Value || tempGpuValue >= (float?)numericUpDown1.Value)
{
soundPlay = true;
blinking_label();
}
else
{
soundPlay = false;
}
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
}
You could do this with a Thread instead of a BackgroundWorker?
With a Thread, in its working subroutine you could put the thread into an infinite sleep inside a try/catch block that catches ThreadInterruptedException. So, as it loops through whatever it's working on, you could look at the value of a boolean flag to know whether or not to sleep, and then call Thread.Sleep(Timeout.Infinite). When you catch ThreadInterruptedException you set the flag to false and continue to execute.
To make the thread resume from your UI, you would set the 'pause' flag to false and call workerThread.Interrupt() on your thread (assuming you called it workerThread, that is).
Idea sourced from here
You may need to wait until cancellation is done before enable/disable button.
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
backgroundWorker1.CancelAsync();
//Wait statement goes here.
this.Cursor=Cursors.AppStarting;
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
button3.Enabled = true;
soundPlay = false;
stop_alarm = true;
}
}
Please see this question:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
if (tempCpuValue >= (float?)numericUpDown1.Value || tempGpuValue >= (float?)numericUpDown1.Value)
{
soundPlay = true;
blinking_label();
}
else
{
soundPlay = false;
}
cpuView();
gpuView();
Thread.Sleep(1000);
}
}
_resetEvent.Set(); // signal that worker is done
}
Related
Long Story Short,
The app I am making will Launch a Game.
The Start button will then Check to make sure the games EXE is running..
IF it is running, it will run a script to press buttons 1, 2, and 3..
After that it will loop that script, but first checking if the game has not crashed (if it crashed it wont run the loop)
My Issue:
While the loop is running, which is using System.Threading.Thread.Sleep,
does not let other functions of the app preform (in this case showing and hiding button, and changing label colors.) The main reason this is important is the button it wont is the Stop button which is suppose to end the looping script.
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
Timer timer;
Stopwatch sw;
public Form1()
{
InitializeComponent();
button4.Visible = false;
button2.Enabled = false;
}
private void timer_Tick(object sender, EventArgs e)
{
label2.Text = sw.Elapsed.Seconds.ToString() + "seconds";
Application.DoEvents();
}
// ===============================================
// BUTTON FUNCTIONS
// ===============================================
// Launch GAME
private void button1_Click(object sender, EventArgs e)
{
// Launch GAME
Process.Start(#"C:\Windows\System32\Notepad.exe");
button2.Enabled = true;
}
// START BOT
private void button2_Click(object sender, EventArgs e)
{
status.Text = #"Starting Bot..";
timer = new Timer();
timer.Interval = (1000);
timer.Tick += new EventHandler(timer_Tick);
sw = new Stopwatch();
timer.Start();
sw.Start();
BotReady(sender, e);
}
// PLAYER DIED
private void button3_Click(object sender, EventArgs e)
{
KillBot(sender, e);
status.Text = #"lol u ded";
}
// STOP THE BOT
private void button4_Click(object sender, EventArgs e)
{
KillBot(sender, e);
status.Text = #"Bot Stopped";
button2.Visible = true;
button4.Visible = false;
button2.Enabled = true;
}
// KILL GAME AND BOT (IF IT CRASHED OR SOMETHING)
private void button5_Click(object sender, EventArgs e)
{
}
// ===============================================
// OTHER FUNCTIONS
// ===============================================
// Target GAME application
private void TargetAQ(object sender, EventArgs e)
{
// this part doesnt work yet.
// Selection.Application and Tab to it
}
// CHECK IF GAME IS STILL RUNNING, KILL BOT IF GAME IS NOT DETECTED
public void CheckStatus(object sender, EventArgs e)
{
Process[] GAME = Process.GetProcessesByName("notepad");
if (GAME.Length == 0)
// GAME NOT running
{
KillBot(sender, e);
button2.Enabled = false;
status.Text = #"GAME is not Running, Bot Stopped.";
uGAME.ForeColor = Color.Red;
button2.Visible = true;
button4.Visible = false;
button2.Enabled = false;
}
else
// GAME IS running
{
status.Text = #"GAME is Running!";
uGAME.ForeColor = Color.Green;
button2.Visible = false;
button4.Visible = true;
}
}
// Verify bot and GAME are running before starting
public void BotReady(object sender, EventArgs e)
{
CheckStatus(sender, e);
if (uGAME.ForeColor == Color.Green)
{
status.Text = #"Bot Started!";
Botting(sender, e);
}
else { status.Text = #"GAME is not running"; }
}
//THE BOT ACTIONS
public void Botting(object sender, EventArgs e)
{
// Check to make sure everything is still running
CheckStatus(sender, e);
TargetAQ(sender, e);
if (uGAME.ForeColor == Color.Green)
{
// all is running, then you good.
Script(sender, e);
}
//GAME died, kill scripts
else {
KillBot(sender, e);
status.Text = #"GAME Crashed:(";
}
}
//Things it does in-game
public void Script(object sender, EventArgs e)
{
status.Text = #"Bot in progress..";
// Use skills in game rotation
System.Threading.Thread.Sleep(3000);
SendKeys.Send("1");
System.Threading.Thread.Sleep(3000);
SendKeys.Send("2");
System.Threading.Thread.Sleep(3000);
SendKeys.Send("3");
// Go back and check the game has not crashed before re-running the script
Botting(sender, e);
}
// STOP THE BOT AND TIME COUNTER
public void KillBot(object sender, EventArgs e)
{
// kill the clock and bot
status.Text = #"Stopping bot...";
timer.Stop();
sw.Stop();
label2.Text = sw.Elapsed.Seconds.ToString() + " seconds";
status.Text = #"Bot Stopped";
}
}
}
The Problem
I have used the project from https://github.com/zaagan/BioMetrix and want to use BackgroundWorker to display a progression during long tasks (Ex: Get Log Data takes about 30 seconds)
What I've done so far
1- Added backgroundWorker1 from Toolbox
2- After InitializeComponent(), I've Added :
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
3- Added those functions:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.Text = (e.ProgressPercentage.ToString() + "%");
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
this.Text = "Canceled!";
}
else if (e.Error != null)
{
this.Text = "Error: " + e.Error.Message;
}
else
{
this.Text = "Done!";
}
}
I was expecting to view the progression percentage on the main Caption title text while retrieving log data from the device.
You need to assign the event handler to the event
worker.DoWork += backgroundWorker_ProgressChanged;
If you have created a Windows Form you need to looking in events page of the Background Worker properties and find the DoWork event, then assign it a function to run.
I have a BackgroundWorker in a WPF application. If a condition is true, I want to immediately stop processing the _DoWork method and go straight to the _RunWorkerCompleted. I'm using .CancelAsync, but the code after this point continues to execute.
How can I cancel out of my _DoWork and fall into _RunWorkerCompleted?
Example:
private BackgroundWorker step1 = new BackgroundWorker();
public MyWindow()
{
InitializeComponent();
step1.WorkerSupportsCancellation = true;
step1.DoWork += new DoWorkEventHandler(step1_DoWork);
step1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(step1_RunWorkerCompleted);
}
private void step1_DoWork(object sender, DoWorkEventArgs e)
{
if (someCondition)
{
step1.CancelAsync();
}
// code I do not want to execute
}
private void step1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// I want to jump here from the cancel point
}
CancelAsync is a method designed to be called by something other than the DoWork handler to indicate that the DoWork handler should stop executing. The DoWork handler should be checking to see if the BGW has requested cancellation and if so, stop executing (either by returning, throwing an exception, or otherwise not performing further work).
In your DoWork handler, check the cancellation state.
private void step1_DoWork(object sender, DoWorkEventArgs e)
{
if (someCondition)
{
step1.CancelAsync();
}
if (!step1.CancellationPending)
{
// code I do not want to execute
}
else
{
e.Cancel = true;
return;
}
}
private void startAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
// Cancel the asynchronous operation.
backgroundWorker1.CancelAsync();
}
}
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
// This event handler updates the progress.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
resultLabel.Text = (e.ProgressPercentage.ToString() + "%");
}
// This event handler deals with the results of the background operation.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
resultLabel.Text = "Canceled!";
}
else if (e.Error != null)
{
resultLabel.Text = "Error: " + e.Error.Message;
}
else
{
resultLabel.Text = "Done!";
}
}
}
}
In Windows form I have Button1, Button2 and Button3. These buttons represent a series of actions that should be carried out in a order from starting action to final action. So that normally I can handle this as follows.
Form1: Form
{
Form_Load(Object sender, event Args e)
{
Button1.Enabled = true;
Button2.Enabled = false;
Button3.Enabled = false;
}
Button1_click(Object sender, event Args e)
{
//Actions
Button2.Enabled = true;
Button1.Enabled = false;
}
Button2_click(Object sender, event Args e)
{
//Actions
Button3.Enabled = true;
Button2.Enabled = false;
}
Button3_click(Object sender, e)
{
//Actions
Button3.Enabled = false;
Button1.Enabled = true;
}
}
In several places I'm doing it in this way. Is this the standard way?
EDIT:
And also in a simple situation like you should have clicked button1 before clicking button2, the above approach is acceptable?
To expand on what Bjarke said, I'm providing a code example.
Form1: Form
{
List<Button> listButtons = new List<Button>();
public void EnableButton(Button btnToEnable)
{
foreach(Button btn in listButtons)
{
//check button name.
//if it is the button to enable, enable it, if not then disable it
btn.Enabled = btn.Name == btnToEnable.Name;
}
}
Form_Load(Object sender, event Args e)
{
listButtons.Add(Button1);
listButtons.Add(Button2);
listButtons.Add(Button3);
EnableButton(Button1);
//Button1.Enabled = true;
//Button2.Enabled = false;
//Button3.Enabled = false;
}
Button1_click(Object sender, event Args e)
{
EnableButton(Button2);
//Actions
//Button2.Enabled = true;
//Button1.Enabled = false;
}
Button2_click(Object sender, event Args e)
{
EnableButton(Button3);
//Actions
//Button3.Enabled = true;
//Button2.Enabled = false;
}
Button3_click(Object sender, e)
{
EnableButton(Button1);
//Actions
//Button3.Enabled = false;
//Button1.Enabled = true;
}
}
I have the following in a button click event:
private void buttonSubmitAchChecks_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy) return;
SubmittingAch(true);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
label_Status.Text = "Submitting checks to ACH ....";
var qry = from ds in checkTrans.IndividualCheck
where ds.SubmitToACH &&
ds.Status == "Entered" &&
ds.CheckAmount > 0 &&
ds.SubmitToACH
select ds;
if (qry.Count() <= 0)
{
label_Status.Text = "Nothing to submit. Check the Check Amount, ACH, and Status fields.";
}
else
{
progressBar1.Maximum = qry.Count();
progressBar1.Minimum = 0;
progressBar1.Step = 1;
backgroundWorker1.RunWorkerAsync(qry);
}
}
My backgroundWorker1_DoWork:
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
}
else
{
var qry = e.Argument as EnumerableRowCollection<CheckTrans.IndividualCheckRow>;
if (qry != null)
{
Thread.Sleep(4000);
//item.Status = ach.SubmitCheck(item);
var ach = new SubmitAchChecks();
foreach (var item in qry)
{
ach.SubmitCheck(item);
backgroundWorker1.ReportProgress(1);
Console.Write("backgroundWorker1_dowork=" + progressBar1.Value.ToString() + "\r\n");
}
}
}
}
My Cancel Button:
private void cancelAsyncButton_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation == true)
{
label_Status.Text = "Cancelling...";
backgroundWorker1.CancelAsync();
}
}
My backgroundWorker1_RunWorkerCompleted:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
label_Status.Text = "Canceled!";
}
else if (e.Error != null)
{
label_Status.Text = "Error: " + e.Error.Message;
}
else
{
label_Status.Text = "Done!";
}
SubmittingAch(false);
}
My backgroundWorker1_ProgressChanged:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value += 1;
Console.Write("progressbar1.value=" + progressBar1.Value.ToString() + "\r\n");
}
I get following output in my debug window when I processed 2 items:
backgroundWorker1_dowork=0
backgroundWorker1_dowork=0
progressbar1.value=1
progressbar1.value=2
The event is firing, but as you can see from the console.write, it's happening AFTER the thread finishes. I get the progressbar scrolling, but only once the dowork has completed.
What have I done wrong on this? I'd like it to update as each item is completed.
It's due to the way threads work. ProgressChange is invoked on the UI thread using BeginInvoke, and therefore on another thread. Meanwhile, the worker thread continues running. Since there is not much work to do, the BackgroundWorker finishes its work before BeginInvoke actually invokes the method, because thread switches don't happen every CPU operation. They happen after quite a few. To avoid this, manually call the method that increments the ProgressBar's value using this.Invoke().