I want to put a function on an endless loop but with a timeout countdown. After each time it perform its function, it should stop for a manually-configured amount of time. If I use Sleep, it freezes everything else. Is there a way that I can do this without affecting the other functions in my project?
private void btn30_Click(object sender, EventArgs e)
{
int hour = DateTime.Now.Hour;
int minute = DateTime.Now.Minute;
int second;
do
{
if (5 + DateTime.Now.Second > 60)
{
second = (DateTime.Now.Second + 5) - 60;
}
else if (5 + DateTime.Now.Second == 60)
{
second = 0;
}
else
{
second = DateTime.Now.Second + 5;
}
if (sc.checkScheduleStarted() == false)
{
sc.Start30(hour, minute, second);
btn30.Text = "5 second waiting";
System.Threading.Thread.Sleep(5000);
}
else
{
sc.Stop();
btn30.Text = "Countdown - 5";
}
} while (loopCycle == true);
}
You're using Task.Sleep() on the main UI thread. Obviously you'll end up freezing the UI. You should consider running your calculations in background with Task.Run
and then make delays with non-blocking thread Task.Delay
:
private void btn30_Click(object sender, EventArgs e)
{
Task.Run(async() =>
{
do
{
// Your stuff here...
// Pick one of the two examples below for your case:
// 1. Updates the UI of a WPF application
Application.Current.Dispatcher.Invoke(() =>
{
// Update the UI here...
});
// 2. Updates the UI of a WinForm application
Invoke(new Action(() =>
{
// Update the UI here...
}));
// Make a delay...
await Task.Delay(5000);
} while (true);
});
}
Note that when you want to update the UI from a background thread you have to somehow execute your code that changes the UI in the main thread (the one that created controls you're updating).
I would recommend:
For WPF - Dispatcher.Invoke
For WinForms - Control.Invoke
Make your click handler asynchronous, and use Task.Delay
instead of Thread.Sleep()
. This will allow the handler to release control to the calling context and allow it to schedule other tasks while waiting for the Delay
to pass.
private async Task btn30_Click(object sender, EventArgs e)
{
int hour = DateTime.Now.Hour;
int minute = DateTime.Now.Minute;
int second;
do
{
if (5 + DateTime.Now.Second > 60)
{
second = (DateTime.Now.Second + 5) - 60;
}
else if (5 + DateTime.Now.Second == 60)
{
second = 0;
}
else
{
second = DateTime.Now.Second + 5;
}
if (sc.checkScheduleStarted() == false)
{
sc.Start30(hour, minute, second);
btn30.Text = "5 second waiting";
await Task.Delay(5000);
//Rest of code
Don't bother with threading. Just drop a Timer control on the form and subscribe to the tick event. The control will call the event within the UI thread and won't freeze the ui.
public class YourForm {
private int Seconds = 5;
private void btn30_Click(object sender, EventArgs e) {
YourTimer.Start();
}
public void YourTimer_Tick(object sender, EventArgs e)
{
Seconds--;
if (Seconds<= 0) {
YourTimer.Stop();
// Do your stuff
}
}
}
Reference : Timer class
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.