I am using the below code to start and stop the foreach loop execution. But start is working fine. I can't stop the loop execution while stop button click. Please help me to do this.
private void btn_start_Click(object sender, EventArgs e)
{
if (txt_rows.Text != "") {
thread = new System.Threading.Thread(new System.Threading.ThreadStart(update));
thread.IsBackground = true;
thread.Start();
}
}
private void Update()
{
//My logic here
}
private void btn_stop_Click(object sender, EventArgs e)
{
lbl_appstatus.Text = "Stop"; // Button click event not fired while run the loop
lbl_appstatus.Update();
lbl_appstatus.ForeColor = System.Drawing.Color.Red;
if (thread != null && thread.IsAlive)
thread.Abort();
}
In your code, if you click twice or more on start button you loos your previous thread objects; Thus you should not create more than one thread.
The "Start" and "Stop" clicks are separate requests to that codebehind. These use separate instances of you Page class, which usually means two separate "thread" variables (you didn't show the declaration).
So on the "Stop" click that thread value is always null.
For an "InProc" session, maybe it's possible to store that thread value in Session, so you can keep the value across requests.
Related
Is it possible to stop an ongoing process with a button click in Windows form application?
For example, let's say there are 2 buttons, "START" and "STOP"
When you press "START", it will start an infinite loop, printing numbers from 1 to infinity.
When I press "STOP", the process should stop at that moment.
But the problem is, I cannot press the "STOP" button as it does not allow me, since there's an ongoing process.
Is there a way to overcome this?
I know there's something called "MethodInvoker", but I have no idea how that works or whether it is relevant to this.
private bool keepRunning = true;
public Form1()
{
InitializeComponent();
}
private void StartBtn_Click(object sender, EventArgs e)
{
var number = 1;
while (keepRunning)
{
Thread.Sleep(1000);
MesgeLabel.Text = "" + number++;
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
//Cannot even click this button
keepRunning = false;
//or
Application.Exit();
}
EDIT 1:
If you need to interact with UI controls, doing it from a background task would throw invalid operation -> illegal cross thread exception. To overcome this,
check Control.InvokeRequired
if(myLabel.InvokeRequired)
myLabel.Invoke(new Action(() => myLabel.Text = newText));
else
myLabel.Text = newText;
You can start a Task by providing a CancellationToken and cancel the operation when the stop button is clicked.
The task will execute the infinite loop on another thread and your main thread (the UI thread) should not be affected and should be accessible.
Try this:
/*
Please add these on top of your form class
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
*/
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
CancellationTokenSource cancellationTokenSource;
CancellationToken cancellationToken;
private void CountToInfinity()
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
Debug.WriteLine(new Random().Next());
}
}
private async void button1_Click(object sender, EventArgs e)
{
if (cancellationTokenSource == null)
{
cancellationTokenSource = new CancellationTokenSource();
cancellationToken = cancellationTokenSource.Token;
Task.Run((Action)CountToInfinity, cancellationToken);
}
}
private void button2_Click(object sender, EventArgs e)
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
}
If you have spawned a new process then you can call kill method.
Process myProcess = Process.Start("Notepad.exe")//starts new process
myProcess.Kill();// kills the process. save reference to myProcess and call kill on STOP button click
If you have started new thread then call abort method to stop the thread.
Thread thread = new Thread(new ThreadStart(method));
thread.Start();
thread.Abort(); // terminates the thread. call abort on STOP button click
When you press the "start" button, the code that runs and prints the numbers will run on the ui thread. (from your explanation, i assume that all you have is the message handler for the button press event and nothing else. e.g.: Not setting up a seperate thread.).
Running an infinite loop on the ui thread means, that you do not get any more time for processing other messages. (the thread that is responsible for processing the ui messages is stuck in your infinite loop.)
So, in order to be able to press the "stop" button, you need to run the code with the infinite loop in a different thread or in a different process altogether. This is what Arjun is trying to tell you. (if you want the code in the infinite loop to access resources from your form app, you need a thread. [the thread is inside the forms app process.])
please note: if you create a thread and run your number printing code inside that thread, this will not be the ui thread. Thus, you will not be able to interact with the forms controls as if you'd be on the ui thread. (i.e.: trying to set the windows.text in order to display your numbers will most likely throw an exception.)
I am implementing a debugger using c#(working on VS2012 -- .Net 4.5), it should work as below: (This is a vbscript debugger which is using msscript.ocx control)
On the line with breakpoint it should wait for the {F5} key and upon having the {F5} key it should move to next code line.
Now the problem is that in the debug method(This method is called upon hitting breakpoint) keeps on moving in the loop checking for the static variable set as true ( The key-press event on the control sets this static variable as true).
The application goes un-responsive and i have to stop it.
Here goes the code for it:
Following code is implemented at the KeyPress event of a TextBox:
Whenever it receive a {F5} key it sets true in a static variable.
static bool dVar;
private void fctb_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.F5)
{
//Setting the static variable true when the control recieves a {F5} key
dVar = true;
}
}
Now Upon hitting the breakpoint following function is called
public void DebugIT()
{
dVar=false
//Waits for the {F5} key press by checking for the static variable
//The Application goes Un-Responsive on this Loop and stops accepting keys
while (dVar!=true)
{
System.Threading.Thread.Sleep(1000);
}
}
}
The issue here is that when it enter the while loop it stops accepting the key-presses and goes unresponsive.
Need a way that suspends the code execution till the time it receives a desired key-press.
Or
Can we have a separate thread which checks for the {F5} key press and does not make the application un-Responsive.
Can anyone please help?
Here is an example of how you can do this.
If you want this exact code to work create a new form and drag-drop two buttons and a textbox on it.
public partial class Form1 : Form
{
ManualResetEvent man = new ManualResetEvent(false);
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
button2.Click += button2_Click;
}
private async void button1_Click(object sender, EventArgs e)
{
textBox1.Enabled = false;//Do some work before waiting
await WaitForF5(); //wait for a button click or a key press event or what ever you want
textBox1.Enabled = true; //Continue
}
private Task WaitForF5()
{
return Task.Factory.StartNew(() =>
{
man.WaitOne();
man.Reset();
}
);
}
private void button2_Click(object sender, EventArgs e)
{
man.Set();
}
}
In the above example when you click button1 the textbox is disabled and when you press the second button is gets enabled again.
And this is done without blocking the UI
You need to add DoEvents into your while loop. See the example from MSDN
I am writing this program that I want to run forever via a while loop and whenever the user presses a certain key on their keyboard it exits the program. I've looked everywhere but I have only seen KeyEvents, but the WindowsForm isn't active while the program is running. Anyone have a solution for me?
Edit: The program takes over the cursor so activating an event on the UI is basically impossible
Edit Two:
public void MainMethod()
{
while (true)
{
if (checkBox1.Checked == true) state = State.PERFORM_ACTION_ONE;
if (checkBox2.Checked == true) state = State.PERFORM_ACTION_TWO;
// More stuff checking which state to assign
switch (state)
{
case State.PERFORM_ACTION_ONE:
DoSomething();
break;
// More cases
// I want it to be able to break anywhere in the while loop
}
}
}
You need to set a HotKey like here Set global hotkeys using C# then using that HotKey to exit the application.
You need to run your infinite loop in a separate thread from the UI thread. And have a infinite loop to check on the variable that can be set from UI thread:
while (keepRunning){
// do stuff
}
and then set event on a button press to change keepRunning to false.
Here is the quick sample:
public partial class Form1 : Form
{
public static bool KeepRunning;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
KeepRunning = true;
Task.Factory.StartNew(() =>
{
while (KeepRunning)
{
Trace.WriteLine("Keep running");
}
});
}
private void button2_Click(object sender, EventArgs e)
{
KeepRunning = false;
Trace.WriteLine("Finished Execution");
}
}
if you start the loop in another thread you could cancel that thread that it is running when you hit the "hot key" or whatever you want to stop it. Check out BackgroundWorker.
Put the loop into a separate Task.
WinForms will continue to run concurrently on the UI thread, so it can continue to receive the user input. When user requests you to stop, you can use the task cancellation mechanism1 to exit from the loop and the task itself.
1 See the "Canceling a Task" section here.
How to use BackgroundWorker in C#?
Actually i'm performing an operation of filling a PDF-Form from method called fill(). It takes more time to show up the result into pdfviewer, so I decided to show up a 'processing image' using a backgroundworker, and tried using it but failing to achieve it
here is my code snippet :
private void bgwLoadFile_DoWork(object sender, DoWorkEventArgs e)
{
this.Invoke((MethodInvoker)delegate()
{
????
});
}
private void bgwLoadFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
}
else if (e.Error != null)
{
}
else
{
picLoading.SendToBack();
}
}
Fill method is called when button FILL is been clicked
private void btnFill_Click(object sender, EventArgs e)
{
if (btnFill.Text == "Fill")
{
bgwLoadFile.RunWorkerAsync();
picloading.BringToFront();
Fill();
}
wat statement should i need to add in DoWork method , if i tried to add FILL() fill is been called twice ...
can any one help me out
Thanks
Add Fill(); to your bgwLoadFile_DoWork and remove it from btnFill_Click
Just a side-note you'll probably want to call your picLoading.SendToBack(); outside of that 'else' as if you error or cancel it will stay there.
So let's try to find some answers:
The method worker_DoWork() will be executed within another thread. By calling within that method this.Invoke() you're going to pass the call back to the gui thread, which makes the usage of the background worker useless. Instead within the worker method you have to call the method that needs some time and doesn't interact with the gui. If this called method produces any result (e.g. has a return value) you should write this information into the variable e.Result.
The method worker_RunWorkerCompleted() will be called within the gui thread again. Allowing you to take the result and let it somehow interact with the gui. Due to the fact, that this method will be executed on the gui thread it should be quite simple (or fast) in its doing otherwise your gui is going to freeze again.
So given these informations lets clean up your code:
private void btnFill_Click(object sender, EventArgs e)
{
if (btnFill.Text == "Fill")
{
// Update the gui for the user
// and start our long running task
// (disable buttons etc, cause the
// user is still able to click them!).
picloading.BringToFront();
bgwLoadFile.RunWorkerAsync();
}
}
private void bgwLoadFile_DoWork(object sender, DoWorkEventArgs e)
{
// Let's call the long running task
// and wait for it's finish.
Fill();
}
private void bgwLoadFile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// We're back in gui thread.
// So let us show some results to the user.
if (e.Cancelled)
{
// To support cancellation, the long running
// method has to check some kind of cancel
// flag (boolean field) to allow fast exit of it.
labelMessage.Text = "Operation was cancelled.";
}
else if (e.Error != null)
{
labelMessage.Text = e.Error.Message;
}
// Hide the picture to allow the user
// to access the gui again.
// (re-enable buttons again, etc.)
picLoading.SendToBack();
}
I need to update my text box continuously after clicking the button but the button should perform its remaining task as it is.
simple is that when click event is performed then Text box should not wait for the completion of click event but to start updating its text continuously.
sample code
using System.threading;
namespace name
{
public class sA
{
public void th()
{
textbox.invoke(new MethodInvoke(()=> textbox.AppendText("hello\n")));
}
private void Button1Click(object sender, EventArgs e)
{
thread cThread=new thread(th);
cThread.start();
while(true)
{
// do any thing
}
}
}
}
Important :: when it performs the event " Cthread.start();" text box should immediately start updating the text while the remaining functions of click event like "while loop" should perform in parallel.
IF this is inside Windows Forms.. then add Application.DoEvents(); anywhere in the loop
e.g.
private void Button1Click(object sender, EventArgs e)
{
thread cThread=new thread(th);
cThread.start();
while(true)
{
// do any thing
textbox.Invalidate();
Application.DoEvents(); // Releases the current thread back to windows form
// NOTE Thread sleep different in Application.DoEvents();
//Application.DoEvents() is available only in System.Windows.Forms
}
}
Hope this help you although late.. :)
Your while(true) block has to happen on another thread as well.
Right now its blocking the UI thread from performing any updates.
Method th() is running on a background thread but the call to Invoke can't run until the UI thread is available again.
If I understood your question correctly, you need to keep updating the TextBox's text while the button click procedure is running inside it's "while" loop. You didn't really specify where will the textbox be updated from, but I will assume that it is coming from the code inside your "while" loop.
As "akatakritos" has stated, your while loop inside the button click is the reason why your application is halting. That happens because the while loop is blocking the User Interface (UI) Thread.
What you should be doing is moving the code inside your "while" loop to run inside a different thread, and use the button click to start this new thread.
Here is a way to do this, maybe not the best, but it will do what you need:
Create a new class:
public class ClassWithYourCode
{
public TextBox TextBoxToUpdate { get; set; }
Action<string> updateTextBoxDelegate;
public ClassWithYourCode()
{ }
public void methodToExecute()
{
bool IsDone = false;
while (!IsDone)
{
// write your code here. When you need to update the
// textbox, call the function:
// updateTextBox("message you want to send");
// Below you can find some example code:
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1000);
updateTextBox(string.Format("Iteration number: {0}", i));
}
// Don't forget to set "IsDone" to "true" so you can exit the while loop!
IsDone = true;
}
updateTextBox("End of method execution!");
}
private void updateTextBox(string MessageToShow)
{
if (TextBoxToUpdate.InvokeRequired)
{
updateTextBoxDelegate = msgToShow => updateTextBox(msgToShow);
TextBoxToUpdate.Invoke(updateTextBoxDelegate, MessageToShow);
}
else
{
TextBoxToUpdate.Text += string.Format("{0}{1}", MessageToShow, Environment.NewLine);
}
}
}
and, inside your button1_Click method, you can add the following code:
private void button1_Click(object sender, EventArgs e)
{
ClassWithYourCode myCode = new ClassWithYourCode();
myCode.TextBoxToUpdate = textBox1;
Thread thread = new Thread(myCode.methodToExecute);
thread.Start();
}
Now, your "while" loop is executing inside a new thread and, whenever you need to update the textbox, you do so from the UI thread, because you cannot update Windows Forms controls from a thread other than the UI thread.