I have two buttons one for start and one for stop in my UI form,and i have one infinite loop that executes some function in my class name programs in a method.The start button is clicked by the user it invokes this method to execute the infinite loop and i need to break this infinite loop when the user clicks the stop button,after that my compiler will break out of this infinite loop and enters to the code inside the button stop click.
I am trying to use the Application.DoEvents() method,this is working well if my infinite loop code is inside of the start button click,but if my infinite loop code is in the new class which is created by me i.e programs,how can use the Application.DoEvents() method to break out of this infinite loop.
Example:
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
this is working well.
But
public class programs
{
public static void infiniteLoop(bool stopBtnClick)
{
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
}
//and my UI code to call this class is
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
programs.infiniteLoop(stopBtnClk);
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
}
but this is not working .
Even if the compiler displays the message "success" when the stop button is clicked, but the debugger still said running in my form.
I hope my question is clear.
And i am kindly requesting you to answer my question as soon as possible and get rid of this problem!
I openly accept your answer if you come especially with a thread.
sorry i am a beginner for C#, but i need to continue on that.
Thank you!!
Don't block the GUI thread. The fact that you have to use Application.DoEvents() to update the GUI is an indicator for bad design. Do the work in a separate worker thread.
BackgroundWorker is predestinated for such a task.
Change signature of your infiniteLoop method like this:
public static void infiniteLoop(ref bool stopBtnClick)
...
The code you have provided is really difficult to read but as far as I can see when you create your infinite loop do:while(looping) // do stuff
Then when you press the Stop button set the bool variable looping to false and it will break out of the loop and show the message.
In the second code snippet, the infinite loop is started in a subroutine that accepts a boolean value as a parameter. How does that subroutine ever get a second chance to take a look at that boolean? It only "sees" the value once, and it's false at that time. It's a scoping question.
Why instead of an infinite loop you use a start stop condition determined by the buttons?
I thinking you can have a variable, just call it
bool stop_loop = false
and your loop
while(!stop_loop){ //CODE HERE }
Now when you click the first button (Start) you call the method (wherever it is) to start the loop. The loop is going to seem endless until you click the button stop and the value of stop_loop become in True.
HTH
Related
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
We are learning multi-threadding today in class and we came across a very curious error. When doing a for loop in our new thread the upper bound of the for loop keeps getting passed. The thread is being killed but then another value will appear and end another thread.
For the purpose of debugging the error I changed the upper bound to 90 to avoid the OutOfRange Exception on the progressbar.
While outputting the counter to the progressing bar and updating the progress bar I got this in my output window.
If i commented out the updating on the progress bar (pbLoad.Value = i;) I got this in my output window
I have tried changing the loop to i<101 and also tried moving where the i++ was but it made no difference
EDIT: This is coming from the BeginInvoke. When i switched it to Invoke it worked but then I will get a deadlock when trying to use the cancel button.
Here is the code:
public partial class Form1 : Form
{
Thread backgroundThread;
bool stopExecution = false;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
stopExecution = false;
btnStart.Enabled = false;
backgroundThread = new Thread(DoDomethingThatTakesAWhile);
backgroundThread.Start();
}
private void DoDomethingThatTakesAWhile()
{
for (int i = 0; i <= 100; i++)
{
if (!stopExecution)
{
Thread.Sleep(100);
if (pbLoad.InvokeRequired)
{
MethodInvoker myMethod
= new MethodInvoker(
delegate
{
if (!stopExecution)
{
pbLoad.Value = i;
Debug.WriteLine(i); //i to output window
}
});
pbLoad.BeginInvoke(myMethod);
}
else
{
pbLoad.Value = i;
}
}
else
{
break;
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
//backgroundThread.Abort();
stopExecution = true;
backgroundThread.Join();
pbLoad.Value = 0;
btnStart.Enabled = true;
}
}
When you call MethodInvoke it will not occurs at that moment, but some time later.
In your scenario you have a chance of following to occurs:
invoked code is finally executed;
the loop is already finished (and i become 101)
you are accessing i directly and you read 101.
And to fix it you can make a copy of i (by passing it as a parameter to invoked method):
pbLoad.BeginInvoke(new Action<int>(a =>
{
if (!stopExecution)
{
pbLoad.Value = a;
Debug.WriteLine(a); //a to output window
}
}), new object[] { i });
P.S: you don't need to check for InvokeRequired, unless you plan to call DoDomethingThatTakesAWhile method directly, which I assume is not the case.
You're using BeginInvoke which explicitly opens the possibility for races. I recommend synchronous invoking.
Furthermore, you are capturing i, not its value. This is racy and only works by accident because you're sleeping.
Either of the changes will fix the problem. Do both of them.
If you can, abolish this low-level use of synchronization and use async/await.
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.
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.
I have a c# form that draws some curves on it. I am trying to draw these curves at a specified interval with random values. I was able to do what I want, but there is a situation that I cannot answer. In the cases below, case 1 has the form repainted very very fast despite the fact that I am using 5 second interval. However, in case 2 if I moved the "Invalidate();" to the other part, then the code works as it is supposed to.
What is the reason for that situation?
Thank you...
Case 1:
private void hizlariHesapla()
{
if (RastgeleDegerCheckBox.Checked == false)
{
// Some code blocks
}
else
{
// Some code blocks
Invalidate();
}
Hesapla(); // Not important for the case
}
private void SurekliCizdir_Tick_1(object sender, EventArgs e)
{
if (RastgeleDegerCheckBox.Checked == true)
{
hizlariHesapla();
}
}
Case 2:
private void hizlariHesapla()
{
if (RastgeleDegerCheckBox.Checked == false)
{
// Some code blocks
}
else
{
// Some code blocks
}
Hesapla(); // Not important for the case
}
private void SurekliCizdir_Tick_1(object sender, EventArgs e)
{
if (RastgeleDegerCheckBox.Checked == true)
{
hizlariHesapla();
Invalidate();
}
}
It sounds as if your Hesapla method can directly or indirectly call back into the hizlariHesapla method. With the Invalidate call outside the loop you will only see it repaint once per timer tick but when it's inside you see the repaint for every time hizlariHesapla is called. Put a breakpoint there and look at the call stack.