method waiting for an winform event - c#

in a programm i've been developing, a method is needed to wait until ENTER is clicked inside a specific textbox (generally, winform event called). i know i shold be doing this with threads, but dont know how to make a method that will do that. more specificly, i don't know how to call the event method on the thread, and cannot call in on Main, because it's blocked until this method is called.
the method stopping the Main thread is:
void WaitForInput()
{
while (!gotInput)
{
System.Threading.Thread.Sleep(1);
}
}
thanks for helpers.

Just subscribe to KeyDown (or KeyPress) event of your textbox:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
// do your stuff
}
}

You can start by changing the WaitForInput method to be threaded by using Tasks like this:
private void WaitForInput()
{
Task.Factory.StartNew(() =>
{
while (!gotInput)
{
System.Threading.Thread.Sleep(1);
}
MessageBox.Show("Test");
});
}
Then catch the KeyPressed event of the textbox and change the state of the boolean gotInput to true like this:
private void KeyDown(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)13)
gotInput = true;
}
Good luck

Use the async/await keywords from .NET 4.5. You could do something like this:
CancellationTokenSource tokenSource; // member variable in your Form
// Initialize and wait for input on Form.Load.
async void Form_Load(object sender, EventArgs e)
{
tokenSource = new CancellationTokenSource();
await WaitForInput(tokenSource.Token);
// ENTER was pressed!
}
// Our TextBox has input, cancel the wait if ENTER was pressed.
void TextBox_KeyDown(object sender, KeyEventArgs e)
{
// Wait for ENTER to be pressed.
if(e.KeyCode != Keys.Enter) return;
if(tokenSource != null)
tokenSource.Cancel();
}
// This method will wait for input asynchronously.
static async Task WaitForInput(CancellationToken token)
{
await Task.Delay(-1, token); // wait indefinitely
}

currently i'm stuck with a dinosaur computer that has XP on it (.NET 2008 and cannot upgrade until april or so). i've ended up following a solution from the comments, and makethe main thread wait and run the entries on threads.
thanks!

Related

C# How to terminate a click-event handler with another click-event

I have a click-event handler to a button that forms an ssh connection. I want to terminate this function with another "cancel" button click.
However, when executing an event handler, "cancel" click event handler doesn't run while the first handler executing. I want to override the first handler with "cancel" handler.
private void button_sshconnection_Click(object sender, EventArgs e)
{ /* some code to create ssh connection */ }
private void button_cancel_Click(object sender, EventArgs e)
{ /* some code to terminate button_sshconnection_Click */ }
I tried a code-structure like the above code but as I said second function doesnt run while the first function running. If the structure is wrong, can someone tell me how to do this job.
Thanks in advance,
Onur
You can try implementing async version of your routine, e.g.
private CancellationTokenSource m_Cancellation;
private async void button_sshconnection_Click(object sender, EventArgs e) {
// if method is executing, do nothing. Alternative: cancel and start again
if (m_Cancellation != null)
return;
try {
using (m_Cancellation = new CancellationTokenSource()) {
var token = m_Cancellation.Token;
await Task.Run(() => {
//TODO: implement your logic here, please, note that cancellation is cooperative
// that's why you should check token.IsCancellationRequested
}, token);
}
}
finally {
m_Cancellation = null;
}
}
private void button_cancel_Click(object sender, EventArgs e) {
// If we can cancel, do it
m_Cancellation?.Cancel();
}

How to pause and resume a backgroundworker thats plotting a chart dynamcally? [duplicate]

Let's say I have a background worker like this:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
//Kill zombies
}
}
How can I make this background worker start and stop using a button on a WinForm?
Maybe you can use a manualresetevent like this, I didn't debug this but worth a shot. If it works you won't be having the thread spin its wheels while it's waiting
ManualResetEvent run = new ManualResetEvent(true);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(run.WaitOne())
{
//Kill zombies
}
}
private void War()
{
run.Set();
}
private void Peace()
{
run.Reset();
}
Use the CancelAsync method.
backgroundworker1.CancelAsync();
In your loop inside the worker thread.
if (backgroundWorker.CancellationPending) return;
This doesn't happen immediately.
This is how to do it (link to answer below)
By stop do you really mean stop or do you mean pause?
If you mean stop, then this is a piece of cake. Create a button click event handler for the button you want to be responsible for starting the background worker and a button click event handler for the one responsible for stopping it. On your start button, make a call to the background worker method that fires the do_work event. Something like this:
private void startButton_Click(System.Object sender,
System.EventArgs e)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
On your stop button, make a call to the method that sets the background worker's CancellationPending to true, like this:
private void cancelAsyncButton_Click(System.Object sender,
System.EventArgs e)
{
// Cancel the asynchronous operation.
this.backgroundWorker1.CancelAsync();
}
Now don't forget to check for the CancelationPending flag inside your background worker's doWork. Something like this:
private void KillZombies(BackgroundWorker worker, DoWorkEventArgs e)
{
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
}
}
}
And your doWork method:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
KillZombies(worker, e);
}
I hope this can steer you in the right direction. Some further readings:
http://msdn.microsoft.com/en-us/library/b2zk6580(v=VS.90).aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
http://msdn.microsoft.com/en-us/library/waw3xexc.aspx
I haven't tested this, I have code somewhere that I'll have to see exactly what I did, but something like this is an adaptation of Fredrik's answer:
private bool _performKilling;
private object _lockObject = new object();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(true)
{
if (_performKilling)
{
//Kill zombies
}
else
{ //We pause until we are woken up so as not to consume cycles
Monitor.Wait(_lockObject);
}
}
}
private void StartKilling()
{
_performKilling = true;
Monitor.Pulse(_lockObject);
}
private void StopAllThatKilling()
{
_performKilling = false;
]
More complete example of this pattern here:
https://github.com/AaronLS/CellularAutomataAsNeuralNetwork/blob/fe9e6b950e5e28d2c99350cb8ff3157720555e14/CellLifeGame1/Modeling.cs

Close form after stopping background worker not working

I have been trying many different thing and can't get this code to work. My code to stop backgroundworker then close window.
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync();
e.Cancel = true;
MessageBox.Show("close"); //Does show
return;
}
base.OnFormClosing(e);
}
During bw worker
if (worker.CancellationPending)
{
MessageBox.Show("Cancel"); // Does not show
//Cancel
e.Cancel = true;
}
On completed background worker
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Completed"); //Does not work
//Check if restart
if (bw_restart)
{
bw_restart = false;
bw.RunWorkerAsync();
}
//If it was cancelled
if (e.Cancelled)
{
this.Close();
}
//If error show error message
else if (e.Error != null)
{
MessageBox.Show(e.Error.ToString()); // Does not show
}
else //No errors or cancelled
{
MessageBox.Show(e.ToString()); //Does not shoiw
}
}
Cancel button
private void cancel_Click(object sender, EventArgs e)
{
bw.CancelAsync(); //Does not work :s
}
It does not close the window, the X when pressed does not do anything, I got it to close the form but not with stopping the background worker, driving me a bit mad. Link to code i got for this problem that not working: How to stop BackgroundWorker on Form's Closing event?
if (e.Cancelled)
That's fundamentally wrong. You can never be 100% sure that it will be set. Canceling a BGW is always a race condition, the BGW might have been busy exiting when you called its CancelAsync() method so never saw the CancellationPending set to true so never assigned e.Cancel = true in the DoWork event handler.
All you know for a fact is that mClosePending is reliable, since it was set to true on the UI thread. So always call Close() it it is set to true, regardless of the e.Cancelled state.
And yes, checking e.Error doesn't hurt either. But still check mClosePending.
As stated in my comment, your BackgroundWorker has ended due to an error, try adding the following at the top of your run worker completed. Once this error has been resolved your question will be more answerable.
if(e.Error != null)
MessageBox.Show(e.Error.toString());//Put a breakpoint here also
CancelAsync doesn't actually abort your thread or anything like that. It sends a message to the worker thread that work should be cancelled via BackgroundWorker.CancellationPending. Your DoWork delegate that is being ran in the background must periodically check this property and handle the cancellation itself.
Look at this:
private BackgroundWorker background;
private void Form1_Load(object sender, EventArgs e)
{
background = new BackgroundWorker();
background.WorkerSupportsCancellation = true;
background.DoWork += BackgroundOnDoWork;
background.RunWorkerCompleted += BackgroundOnRunWorkerCompleted;
background.RunWorkerAsync();
}
private void BackgroundOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
MessageBox.Show("stop");
}
private void BackgroundOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
// your doWork loop should check if someone don't call background.CancelAsync();
while (!background.CancellationPending)
{
// do something
}
}
private void ButtonClick(object sender, EventArgs e)
{
background.CancelAsync();
}

Is CancelAsync working or not?

I've made a small app where Form is threaded (using BackgroundWorker), and in the form I'm calling a function QuitApplication in Program class when I want to quit.
The DoWork looks like this:
static void guiThread_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
if (Program.instance.form != null)
{
Program.instance.form.UpdateStatus(Program.instance.statusText, Program.instance.statusProgress);
}
Thread.Sleep(GUI_THREAD_UPDATE_TIME);
}
}
and in the Form1 class i have this method attached to the closing of the window:
void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Program.instance.SetStatus("Closing down...", 0);
Program.QuitApplication();
}
So what i want is to ensure that everything quits when I press the X on the window. However, the if( worker.CancellationPending == true ) never hits... why is this?
QuitApplication looks like this:
public static void QuitApplication()
{
Program.instance.guiThread.CancelAsync();
Application.Exit();
}
And Im using guiThread.WorkerSupportsCancellation = true
CancelAsync is setting the CancellationPending property, but then you immediately quit the application without giving the background thread a chance to detect that and shut down. You need to change your UI code to wait for the background thread to finish.
Personally, when I write apps like this, I make the form close button act like a Cancel button rather than quit immediately. It's a lot safer for the end user. For example:
private void abortButton_Click(object sender, EventArgs e) {
// I would normally prompt the user here for safety.
worker.CancelAsync();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
if(worker.IsBusy) {
// If we are still processing, it's not very friendly to suddenly abort without warning.
// Convert it into a polite request instead.
abortButton.PerformClick();
e.Cancel = true;
}
}

Pause and Resume a For-Loop in C#

I'm working on a windows App in C#, I have a for-loop which update something in a loop, and I have 3 buttons on the form named "Stop,Pause,Resume". So the purpose is as same as the buttons named. Does anyone know how to do this?
Here is the Loop
private void btnCompleteAuto_Click(object sender, EventArgs e)
{
setGeneralValue();
for (int i = 1; i <= autoGridView.Rows.Count - 1; i++)
{
if (SRP == "Pause") // this is what I was thinking but it won't work
{ // it will step into end-less loop
do // how to stop this loop on "Resume" button click
{
}while(SRP!="Resume")
}
car = false;
try
{
MemberID = Convert.ToInt64(autoGridView.Rows[0].Cells["Member_ID"].Value);
DispID = Convert.ToString(autoGridView.Rows[0].Cells["Disp_Id"].Value);
Mobile = Convert.ToString(autoGridView.Rows[0].Cells["Mobile"].Value);
DueDate = Convert.ToString(autoGridView.Rows[0].Cells["Due_Date"].Value);
}
catch (Exception)
{
MessageBox.Show("Row Not Found");
}
AutoRecharge(network_name, pack_name, Mobile, Mobile, Convert.ToString(autoGridView.Rows[0].Cells["Rck_Amt"].Value), vendor_id, vendor_pwd, pack_id, oxinetwork_id);
autoGridView.Rows.RemoveAt(0);
}
}
Here are the 3 button events in which I'm setting a variable
private void btnPause_Click(object sender, EventArgs e)
{
SRP = "Pause";
}
private void btnStop_Click(object sender, EventArgs e)
{
SRP = "Stop";
autoGridView.DataSource = "";
}
private void btnResume_Click(object sender, EventArgs e)
{
SRP = "Resume";
}
The reason this doesn't work as you expect is this:
A Windows Forms application uses a single UI thread, which continually processes incoming messages from a queue. Any event handlers you attach to the events of a Windows Forms control get sent to this queue and processed by the UI thread as quickly as possible.
Your btnCompleteAuto_Click is one such handler. Once it starts, nothing else will be processed by the UI thread until it exits. Thus any other handlers you attach to other events (btnPause_Click, btnStop_Click, etc.) must wait their turn, as they will run on the same (UI) thread.
If you want pause/resume functionality, this has to be achieved on a separate thread.
A possible way to implement it might be to use a BackgroundWorker, as suggested by saurabh.
Here is a rough sketch of what your updated code might look like (I have not even attempted to compile this, let alone debug it; it's intended only as a basic outline of how you might accomplish this functionality).
You need to be aware, however, that accessing UI controls directly from a non-UI thread is a no-no. Use a mechanism such as the BackgroundWorker.ProgressChanged event to handle any UI updates that you need to happen based on activity on a non-UI thread.
ManualResetEvent _busy = new ManualResetEvent(false);
private void btnCompleteAuto_Click(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
{
_busy.Set();
btnAutoCompleteAuto.Text = "Pause";
backgroundWorker.RunWorkerAsync();
}
else
{
_busy.Reset();
btnAutoCompleteAuto.Text = "Resume";
}
btnStop.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
_busy.Set();
backgroundWorker.CancelAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// for (something)
// {
_busy.WaitOne();
if (backgroundWorker.CancellationPending)
{
return;
}
// Do your work here.
// }
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_busy.Reset();
btnAutoCompleteAuto.Text = "Start";
btnStop.Enabled = false;
}
After Reading your actual requirement in our comment , i would suggest that use Background worker class which supports cancellation of running process.
See here

Categories