dispatcherTimer not restarting - c#

I'm implementing a countdown in my app
private async void Window_Activated(object sender, WindowActivatedEventArgs args)
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0,1,0);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, object e)
{
TimeSpan timeSpan = new TimeSpan(blockTime.Hours, blockTime.Minutes, blockTime.Seconds);
if (timeSpan != TimeSpan.Zero)
{
timeSpan = timeSpan.Subtract(TimeSpan.FromMinutes(1));
Countdown_TexBlock.Text = String.Format("{0}:{1}", timeSpan.Hours, timeSpan.Minutes);
dispatcherTimer.Start();
}
else
{
dispatcherTimer.Stop();
}
}
The code works but only one time
For example I put 15 minutes in the blocktime (the time that the countdown will be running)
after a minute the countdown.text would be 0:14.
So only works after the first minute
Is not supposed to be restarted with dispatcher.start()

In the code that you posted, I don't see the blockTime variable being changed to any other value than it has in the beginning. This means that on every tick of dispatchTimer the value of the timeSpan.Subtract expression will always evaluate to the same 14 minutes. In your code, that 14 minutes is assigned to a local vaiable that is disposed when the tick is over. This gives the appearance that the dispatchTimer has stopped issuing Tick when it hasn't.
Here's what I ran that works as expected (for testing, I changed the minutes to seconds to make it observable in a reasonable time).
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
// Create the dispatch timer ONCE
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += DispatcherTimer_Tick;
dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
// This will restart the timer every
// time the window is activated
this.Activated += (sender, e) =>
{
startOrRestartDispatchTimer();
};
}
private void startOrRestartDispatchTimer()
{
dispatcherTimer.Stop(); // If already running
blockTime = TimeSpan.FromSeconds(15);
Countdown_TexBlock.Text = blockTime.ToString();
dispatcherTimer.Start();
}
private void DispatcherTimer_Tick(object sender, object e)
{
if (blockTime > TimeSpan.Zero)
{
blockTime = blockTime.Subtract(TimeSpan.FromSeconds(1));
Countdown_TexBlock.Text = blockTime.ToString();
if (blockTime == TimeSpan.Zero)
{
Countdown_TexBlock.Text = "Done";
dispatcherTimer.Stop();
}
}
}
TimeSpan blockTime = TimeSpan.FromSeconds(15);
private DispatcherTimer dispatcherTimer;
// This will restart the timer when the button is clicked.
private void buttonRestart_Click(object sender, RoutedEventArgs e) =>
startOrRestartDispatchTimer();
}

Related

C# DispatchTimer WPF Countdown Timer

I have a WPF application that includes a countdown timer, I'm stuck with the formatting part of it, I have little to no experience with programming and this is my first time using c#. I want to countdown from 15 minutes using DispatchTimer, but as of now, my timer only counts down from 15 seconds, any ideas?
My countdown timer so far:
public partial class MainWindow : Window
{
private int time = 15;
private DispatcherTimer Timer;
public MainWindow()
{
InitializeComponent();
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0,0,1);
Timer.Tick += Timer_Tick;
Timer.Start();
}
void Timer_Tick(object sender, EventArgs e) {
if (time > 0)
{
time--;
TBCountDown.Text = string.Format("{0}:{1}", time / 60, time % 60);
}
else {
Timer.Stop();
}
}
The output looks like this:
A better approach would be to do it with a TimeSpan rather than an int with a number. Setting the TimeSpan value in the following application will do the countdown as I want.
TimeSpan.FromMinutes for minutes
TimSpan.FromSeconds for seconds
You can check here for more detailed information.
public partial class MainWindow : Window
{
DispatcherTimer dispatcherTimer;
TimeSpan time;
public MainWindow()
{
InitializeComponent();
time = TimeSpan.FromMinutes(15);
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
dispatcherTimer.Tick += DispatcherTimer_Tick;
dispatcherTimer.Start();
}
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if (time == TimeSpan.Zero) dispatcherTimer.Stop();
else
{
time = time.Add(TimeSpan.FromSeconds(-1));
MyTime.Text = time.ToString("c");
}
}
}
Xaml Code
<Grid>
<TextBlock Name="MyTime" />
</Grid>
You initialise the DispatchTimer with an interval of 1 second: Timer.Interval = new TimeSpan(0,0,1);
And every TimerTick you decrement your timefield.
So, timeshould start of with the total number of seconds you want to count down. If you start with 15, your countdown timer will count down from 15 seconds to zero.
If you want it to count down for 15minutes, you have to initialise time to 900 (15 x 60'').

C# - Win Form stopping Timer tick

This is my implementation of a Win Form app that has a countdown timer:
readonly DateTime myThreshold;
public Form1()
{
InitializeComponent();
myThreshold = Utils.GetDate();
Timer timer = new Timer();
timer.Interval = 1000; //1 second
timer.Tick += new EventHandler(t_Tick);
timer.Start();
//Threshold check - this only fires once insted of each second
if (DateTime.Now.CompareTo(myThreshold) > 0)
{
// STOP THE TIMER
timer.Stop();
}
else
{
//do other stuff
}
}
void t_Tick(object sender, EventArgs e)
{
TimeSpan timeSpan = myThreshold.Subtract(DateTime.Now);
this.labelTimer.Text = timeSpan.ToString("d' Countdown - 'hh':'mm':'ss''");
}
The wanted behavior is to stop the timer and the tick function when the threshold is reached.
This now does not happens because the check is only executed once since it is placed in the Form1 initialization.
Does exist a way to add this check in a way to immediately stop the Timer once a condition has been meet?
If we define timer as a class field (so it can be accessed from all methods in the class), then we can just add the check to the Tick event itself, and stop the timer from there:
private Timer timer = new Timer();
void t_Tick(object sender, EventArgs e)
{
// Stop the timer if we've reached the threshold
if (DateTime.Now > myThreshold) timer.Stop();
TimeSpan timeSpan = myThreshold.Subtract(DateTime.Now);
this.labelTimer.Text = timeSpan.ToString("d' Countdown - 'hh':'mm':'ss''");
}

WPF / C# (No MVVM) Timer with Countdown Clock

Good day all,
I'm struggling with a coding problem and I need some help. My process requires a 300 second (5 min) timer that fires an event to refresh a Grid Control. That works just fine. The problem is, I need to countdown the 5 mins/300 seconds to the user so they know the next fresh happens in "X" seconds. The goal is to countdown, refresh, and show the user the next refresh.
All code samples below are examples of things I tried.
I have code that works for the refresh, but something strange happens after the first execution. The timer counts down to 0, refreshes, and then restarts at 300 seconds again (good), but each tick down flashes a second timer behind it. So I see 300, 299, 298, ... and then another 300, 299, 298, ...; therefore, it looks like 300, 299, 298, 300, 297, 299, 296, 298, etc. It's nauseating to watch. Let alone trying to watch 20 minutes in...
My 300-second timer is a System.Timers.Timer int eh below example (Reminder, this works):
public partial class MasterControl
{
private Timer _t;
public MasterControl()
{
InitializeComponent();
}
public void Dispose()
{
_t?.Dispose();
_handle?.Dispose();
}
private void Master_OnLoaded(object sender, RoutedEventArgs e)
{
var fd = new FillMaster();
GridMaster.ItemsSource = fd.GridPopulate("TblName", App.UserName);
_t = new Timer();
_t.Elapsed += OnTimedEvent;
_t.Interval = 300000;
_t.Enabled = true;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Dispatcher.Invoke(() =>
{
try
{
var fd = new FillMaster();
GridMaster.ItemsSource = fd.GridPopulate("TblName", App.UserName);
}
catch (SqlException)
{
/* swallow */
}
});
}
}
What I tried to do was add a countdown that fills a label.
I added
private TimeSpan _time;
private DispatcherTimer _timer;
And I adjusted the OnTimedEvent code to the below example and it didn't work. This is where it started to double up on refresh. I tried GC to see if that would work. No dice.
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Dispatcher.Invoke(() =>
{
try
{
var fd = new FillMaster();
GridMaster.ItemsSource = fd.GridPopulate("IntakeCheckList", App.UserName);
TbCountDown.Content = "";
_time = TimeSpan.FromSeconds(60);
_timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
{
TbCountDown.Content = _time.ToString("c");
if (_time == TimeSpan.Zero)
{
_timer.Stop();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
_time = _time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
_timer.Start();
}
catch (SqlException)
{
/* swallow */
}
});
}
I also found some code that casued the same problem.
private void Countdown(int count, TimeSpan interval, Action<int> ts)
{
var dt = new DispatcherTimer {Interval = interval};
dt.Tick += (_, a) =>
{
if (count-- == 0)
dt.Stop();
else
ts(count);
};
ts(count);
dt.Start();
}
Then I added the following to the to OnTimedEvent
Countdown(30, TimeSpan.FromSeconds(5), cur => TbCountDown.Content = cur.ToString());
As seen here
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Dispatcher.Invoke(() =>
{
Countdown(30, TimeSpan.FromSeconds(5), cur => TbCountDown.Content = cur.ToString());
try
{
var fd = new FillMaster();
GridMaster.ItemsSource = fd.GridPopulate("IntakeCheckList", App.UserName);
}
catch (SqlException)
{
/* swallow */
}
});
}
This also failed with the exact same problem.
Ultimately, is there a way to get the countdown from the System.Timers.Timer or something else you can help me with?
Thank you!
You don't actually need more than a simple DispatcherTimer and a DateTime that is cyclically reset to the current time + 300 seconds.
public partial class MainWindow : Window
{
private readonly DispatcherTimer timer = new DispatcherTimer();
private DateTime endTime;
public MainWindow()
{
InitializeComponent();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += new EventHandler(OnTimerTick);
timer.Start();
}
private void OnTimerTick(object sender, EventArgs e)
{
var now = DateTime.Now;
if (endTime < now)
{
endTime = now.AddSeconds(300);
}
label.Content = (endTime - now).ToString(#"mm\:ss");
}
}

Preventing a System.Windows.Forms.Timer from accumulating Intervals?

I'm coding a Family Feud game in C# and after each answer is submitted the 30-second timer is supposed to reset. The problem is I'm accumulating 1-second Intervals so that the counter is counting down faster and faster. I can't figure out how to prevent the Intervals from accumulating. I want it to stay a fixed 1 seconds no matter how many times the button is pressed.
Code:
public System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
public int time = 30;
private void Check_Click(object sender, RoutedEventArgs e)
{
time = 30;
_timer.Tick += timer_Tick;
_timer.Start();
uxLabel1.Content = time.ToString();
//additional code
}
private void timer_Tick(object sender, EventArgs e)
{
_timer.Interval = 1000;
time--;
if (time == 0)
{
_timer.Stop();
strike();
}
uxLabel1.Content = time.ToString();
}
Don't put _timer.Tick += timer_Tick; in the button click code, put it once in the constructor of your form and have that be the only event registration.
public partial class YourForm : Form
{
public YourForm()
{
InitializeComponets();
_timer = new System.Windows.Forms.Timer();
_timer.Tick += timer_Tick;
_timer.Interval = 1000;
}
private System.Windows.Forms.Timer _timer;
private int time = 30;
private void Check_Click(object sender, RoutedEventArgs e)
{
time = 30;
_timer.Start();
uxLabel1.Content = time.ToString();
//additional code
}
private void timer_Tick(object sender, EventArgs e)
{
time--;
if (time == 0)
{
_timer.Stop();
strike();
}
uxLabel1.Content = time.ToString();
}
}

Countdown Timer in a strip status label c#

My program has a parameter that starts up the winform and waits x number of seconds before it runs a function. Currently I am using Thread Sleep for x seconds and then the function runs. how can I add a timer in the strip status label?
so that it says: x Seconds Remaining...
Instead of blocking thread execution, simply call your method when required timeout passes. Place new Timer to your form, and set it's Interval to 1000. Then subscribe to timer's Tick event and calculate elapsed time in event handler:
private int secondsToWait = 42;
private DateTime startTime;
private void button_Click(object sender, EventArgs e)
{
timer.Start(); // start timer (you can do it on form load, if you need)
startTime = DateTime.Now; // and remember start time
}
private void timer_Tick(object sender, EventArgs e)
{
int elapsedSeconds = (int)(DateTime.Now - startTime).TotalSeconds;
int remainingSeconds = secondsToWait - elapsedSeconds;
if (remainingSeconds <= 0)
{
// run your function
timer.Stop();
}
toolStripStatusLabel.Text =
String.Format("{0} seconds remaining...", remainingSeconds);
}
You can use a Timer:
public class Form1 : Form {
public Form1(){
InitializeComponent();
t = new Timer {Interval = 1000};
t.Tick += Tick;
//try counting down the time
CountDown(100);
}
DateTime start;
Timer t;
long s;
public void CountDown(long seconds){
start = DateTime.Now;
s = seconds;
t.Start();
}
private void Tick(object sender, EventArgs e){
long remainingSeconds = s - (DateTime.Now - start).TotalSeconds;
if(remainingSeconds <= 0) {
t.Stop();
toolStripStatusLabel1.Text = "Done!";
return;
}
toolStripStatusLabel1.Text = string.Format("{0} seconds remaining...", remainingSeconds);
}
}

Categories