Stop a running loop over action in form - c#

I have a program that run in a loop. it's this
private void ReadCamAuto_Click(object sender, EventArgs e)
{
this.serialPort1.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
RunReadCamAuto = true;
while (RunReadCamAuto)
{
serialPort1.WriteLine("2,2,2,2");
CreatePic(4, 4);
}
this.serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
}
but the problem is then I'm in the While loop I cant press any other Button in my program so it is not possible to stop. I have no idea how to stop it ?
I tried to press a button who set the RunReadCamAuto to false and Console.ReadKey()
I'm Using:
c# Form App
MS VS 2010

You cannot expect user interface to work while the main thread is busy doing some work in a loop. Use BackgroundWorker object to fire desired loop in it - it's automatically invoked on other thread and from your main thread you can easily send the message to stop its work.
You need to assign your method to BackgroundWorker's DoWork event and then from your form just call myBackgroundWorker.RunWorkerAsync(). Then by calling myBackgroundWorker.CancelAsync() you will change its CancellationPending property to true, which you can be constantly checking in your loop to break execution.
Please see here.

Related

Button Click Event not updating textbox until Finished

Here's a C# code, What happens is when qsubmit button is clicked, program straight away displays "wait..!".
When I debug the program it is found that when I click and function executes textbox1.text = "Hello"; but doesn't updates textbox, it updates only when the control goes off the event function, when that happens value of textbox has already been changed to "wait..!". I want to know why it doesn't updates textbox instantly(If that would have done, I would have seen the text during Thread.Sleep())
private void Button_QSubmit_Click(object sender, EventArgs e)
{
textBox1.Text = "Hello";
Thread.Sleep(1000);
textBox1.Text = "Wait..!";
}
The UI thread is responsible to redraw the windows. So as long as you are doing this inside the UI Thread (e.g. a Button click event), the process is busy with your code and the window is not drawn.
A easy solution could be the use of an Timer. Just add an timer and in the button click you start it (e.g. you set itup to fire in 1 second).
The Timer Event then will simply set the Text.
https://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx shows details about the Timer class.
You are hanging the UI Thread by calling Thread.Sleep from the Main Thread (UI), to update the text box you have to let the UI thread do its job outside your function to update the UI..anyway call Application.DoEvents() before the sleep. But calling Application.DoEvents() is a bad design

C#: How to execute thread without halting program execution

I am making a memory game. Whenever user clicks on a button, an image is revealed. Then user has to click on another button. If both images match, then buttons are replaced by a tick mark. If not, then there is a 1 sec gap for the user to memorize the image location..and then again, images are hidden and buttons are shown.
I do the 1 sec gap by
Thread.Sleep(1000)
I have embedded a countdown timer in the game whose duration is 30 sec. I have placed a label which shows the 30 second countdown on each clock tick.
Now the actual problem is, that whenever Thread.Sleep(1000) is invoked, the timer halts. And after 1 sec, it resumes. I want this timer to execute regardless of Thread. Please help.
It's a little hard to understand exactly what you are asking, so apologies if I've misunderstood you, but I think you are asking how you can update the UI using a timer on a new thread without blocking the UI thread? The answer is that you cannot update a UI control in a thread other than the one that it was created in. Instead you have to create a delegate to do it for you.
So, this gives you an exception because the callback UpdateText at the end of the timer executes on the timer thread, not the main UI thread:
private void button1_Click(object sender, EventArgs e)
{
System.Threading.Timer timer = new System.Threading.Timer(UpdateText, null, 1000, System.Threading.Timeout.Infinite);
}
public void UpdateText(object state)
{
this.textBox1.AppendText("Ouch!" + Environment.NewLine);
}
Whereas, this works as expected: When you click the button, one second later the word "Ouch!" appears in the text box. This is because the use of the BeginInvoke method on the textbox control with the MethodInvoker delegate causes the delegate to execute on the thread that owns the control (i.e. the main UI thread) rather than on the timer thread:
private void button1_Click(object sender, EventArgs e)
{
System.Threading.Timer timer = new System.Threading.Timer(UpdateText, null, 1000, System.Threading.Timeout.Infinite);
}
public void UpdateText(object state)
{
MethodInvoker action = delegate
{
this.textBox1.AppendText("Ouch!" + Environment.NewLine);
};
this.textBox1.BeginInvoke(action);
}

How do I correctly hide a button and show it after my BackgroundWorker does something?

This is what I've tried so far:
Put button.Visible = false into my form's initializer and put button.Visible = true to the end of my backgroundWorkers's DoWork event.
This causes the program to freeze after the BackgroundWorker does its work.
I don't understand why.
Put button.Visible = false into my form's initializer and put button.Visible = true after my backgroundWorker1.RunWorkerAsync() call.
This doesn't work correctly because it displays the button right after the BackgroundWorker starts its work.
I do understand why this is happening.
Put button.Visible = false and doneEvent = new AutoResetEvent(false) into my form's initializer, then put doneEvent.WaitOne() and button.Visible = true after my backgroundWorker1.RunWorkerAsync() call.
This way, everything works fine except that the ProgressBar I have in my form stops working correctly (it doesn't show progress until all the work is finished).
I might have an intuitive idea on why this is happening, but I don't really understand it and I don't know how to solve it.
You should not call any method/property on your button while your code runs inside the DoWork event because this code is in a different thread than the thread where the button has been created.
The BackgroundWorkwer use a well defined set of events to handle situations where you need to update your interface and you should use these events for that task.
For example you could set the property WorkerReportsProgress to true, subscribe to the event ProgressChanged and call backgroundWorker1.ReportProgress(...); inside the DoWork event to update your interface while your background work progress.
In your case probably you need to subscribe to the event RunWorkerCompleted and show your button in that event
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled && e.Error == null)
{
button.Visible = true;
}
}
In the link to the MSDN page for BackgroundWorker there is a sample that demonstrate how to update a progress bar while the DoWork event runs a complex task.

Show wait message while application exit

I have the following code, Some times ArchiveFiles() take more time to complete its execution.
When user clicks exit option more than one time from context menu, Application becomes non responding if ArchiveFiles() takes more time. How can I show a wait message when he clicks the exit option again?
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
ArchiveFiles();
Application.Exit();
}
Thanks
Bhaskar
You can use BackgroundWorker.
Using BackgroundWorker, you will be able to execute time consuming tasks such as the one you have on another thread so that the UI doesn't freeze. You will be able to report the progress of that task, then report it accomplishement and executing what ever logic you need after its completion.
Handle the BackgroundWorker.DoWork event to start the operation that performs the potentially time-consuming work.
Handle BackgroundWorker.ProgressChanged event to report the progress of an asynchronous operation to the user.
Finaly, handle BackgroundWorker.RunWorkerCompleted event to implement whatever logic you want to be implemented after the task has been completed.
Refer to the following:
BackgroundWorker Component Overview
C# BackgroundWorker Tutorial
Create a new WaitingForm and put an image control on the form and use the below .gif in that image control which which automatically animate. Then use the code below:
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
using (var wait = new WaitingForm())
{
wait.Show();
ArchiveFiles();
Application.Exit();
}
}
This may not be the best solution but it is the quickest. If you want the form to be a dialog, use wait.ShowDialog(); instead and carry ArchiveFiles(); Application.Exit();
functions inside it (if that is a probability).
You'd have to run ArchiveFiles asynchronously, by either using a thread or task, or making some delegate and using its BeginInvoke method.
You should use then some synchronization object like ManualResetEvent so the main thread don't continue executing, calling Application.Exit(). Or you could use some event to know when the operation finishes and then call Application.Exit() (or call it inside ArchiveFiles), but I find that to be worse.

Why is this C# timer code not working?

I need to be able to disable a button for 1.5 seconds at a time for an application I'm writing. An image is displayed, a user clicks a button, and then another image is displayed. I need to make sure that the user doesn't click the button again too quickly.
So, when the image is displayed, I call this function:
//when a new image is displayed, start the timer and disable the 'done' button
//for 1.5 seconds, to force people to stop pressing next so quickly
System.Timers.Timer mTimer;
void TimerStart() {
Done.IsEnabled = false;
mTimer = new System.Timers.Timer();
mTimer.Interval = 1500;
mTimer.Start();
mTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerEnd);
}
The TimerEnd code looks like:
void TimerEnd(object sender, EventArgs eArgs) {
if (sender == mTimer){
Done.IsEnabled = true;
mTimer.Stop();
}
}
The 'Done.IsEnabled' line gets hit, but the button is not reenabled and the timer doesn't stop firing. What am I doing wrong here? If it matters, this is a WPF app.
Use DispatcherTimer instead
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(someInterval);
timer.Tick += new EventHandler(someEventHandler);
timer.Start();
private void someEventHandler(Object sender, EventArgs args)
{
//some operations
//if you want this event handler executed for just once
// DispatcherTimer thisTimer = (DispatcherTimer)sender;
// thisTimer.Stop();
}
Basically you are trying to debounce the button, to prevent too quick clicks. Rather than use a timer save the previous click time in millis, if the button is clicked again within a short time ignore the next event.
The timer event is raised on a different thread. When working with the winforms controls, you need to make sure you Invoke them from the same thread where they were called.
When working with WPF there is no guarantee that updates made to UI controls on non-UI threads will work as expected. In many cases you will get an exception when you do this.
In your Timer elapsed handler you need to use the BeginInvoke/EndInvoke paradigm and put your button enabling logic in there to ensure that this code runs on the UI thread instead of Begin/End Invoke
There is a SynchnornizationContext available as well which can be accessed by calling SynchronizationContext.Current . You'll need to cache this before you make the timer call since SynchronizationContext.Current will be null in non-UI threads.
This link talks about this as well.

Categories