i have a Textblock (tbTime) which shows the countdown timer. when it gets zero, the Textblock (tbTime) shows still the zero values. But i wanna make this Textblock (tbTime) disappear, after the countdown timer reaches to zero.
Could anyone help me, please?
C# Code
public partial class InfoScreen : Window
{
DispatcherTimer timer;
TimeSpan time;
public InfoScreen()
{
InitializeComponent();
AppearingNext();
time = TimeSpan.FromSeconds(10);
timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
{
tbTime.Text = time.ToString("ss");
if (time == TimeSpan.Zero) timer.Stop();
time = time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
if (tbTime.Text == "00") //My code doesn't work!
{
tbTime.Visibility = Visibility.Hidden;
}
}
private async void AppearingNext()
{
await Task.Delay(TimeSpan.FromSeconds(10));
VisbilityPanel.Visibility = Visibility.Visible;
}
private void AgreementClick(object sender, RoutedEventArgs e)
{
var registration = new Reset_Register();
registration.Show();
Close();
}
}
One solution is put your code that hide the textblock inside the callback of the timer:
timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate {
tbTime.Text = time.ToString("ss");
if (tbTime.Text == "00") {
tbTime.Visibility = Visibility.Hidden;
}
if (time == TimeSpan.Zero) timer.Stop();
time = time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
Related
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();
}
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");
}
}
I'm trying to make an alarm to ring on specific times ( for example; every five minutes after 9:30 am till 4 pm). So, I want to write a code that rings in 9:30 and 9:35 and ... . but with every approach ultimately I get an error. in my code I have a string that includes the times, but I cannot use that string or group in a if(...) to make the alarm. it's fine with just one number with var..., where am I wrong?
{
public partial class Form1 : Form
{
System.Timers.Timer timer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
DateTime currentTime = DateTime.Now;
string[] DailyTime = { 093000, 093500 };
if (((currentTime.Hour * 10000) + (currentTime.Minute *100) + currentTime.Second) == DailyTime)
{
timer.Stop();
try
{
SoundPlayer player = new SoundPlayer();
player.SoundLocation = #"C:\Windows\Media\Time interval alarm\FiveH.wav";
player.Play();
private void Form1_Load(object sender, EventArgs e)
{
timer = new System.Timers.Timer();
timer.Interval = 1000 * 60 * 5; //5 minutes
timer.Elapsed += Timer_Elapsed;
InitializeTimer(); //this method makes sure the timer starts at the correct time
}
The timer initialization method:
private async void InitializeTimer()
{
while (!timer.Enabled) //keep looping until timer is initialized
{
//if the minute is a multiple of 5 (:00, :05, ...) start the timer
if (DateTime.Now.Minute % 5 == 0 && DateTime.Now.Second == 0)
{
timer.Start();
TriggerAlarm(); //trigger the alarm initially instead of having to wait 5min
}
else
{
await Task.Delay(100);
}
}
}
You could store the times and alarm paths in a dictionary:
Dictionary<TimeSpan, string> dict = new Dictionary<TimeSpan, string>()
{
{ new TimeSpan(9, 30, 0), #"C:\Windows\Media\Time interval alarm\FiveH.wav" },
{ new TimeSpan(9, 35, 0), #"C:\Windows\Media\Time interval alarm\Whatever.wav" },
{ new TimeSpan(9, 40, 0), #"C:\Windows\Media\Time interval alarm\Whatever1.wav" },
{ new TimeSpan(9, 45, 0), #"C:\Windows\Media\Time interval alarm\Whatever2.wav" },
//...
{ new TimeSpan(16, 0, 0), #"C:\Windows\Media\Time interval alarm\Whatever3.wav" }
};
The Timer_Elapsed event, which will trigger every 5 min since the alarm is started
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
TriggerAlarm();
}
The method that plays the sound
private static void TriggerAlarm()
{
TimeSpan alarmTime = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, 0);
if (dict.TryGetValue(alarmTime, out string alarmFile))
{
using (SoundPlayer player = new SoundPlayer(alarmFile))
{
player.Play();
}
}
else
{
//this alarm time is not found in the dictionary,
//therefore, no alarm should be played at this time (e.g. 16:05:00)
}
}
I am looking to allow a timer to continue counting down even when a message box is shown. The message box is shown when the timer hits 30 seconds and zero seconds. However, currently the timer stops until the message box is closed by the user. My current code is below;
_Time = TimeSpan.FromSeconds(60);
_Timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate
{
O2_Timer.Text = _Time.ToString("c");
if (_Time == TimeSpan.FromSeconds(30))
{
MessageBox.Show("timer is at 30 seconds");
}
if (_Time == TimeSpan.Zero)
{
_Timer.Stop();
MessageBox.Show("timer done");
Sub_Depth.Text = null;
}
_Time = _Time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
_Timer.Start();
Thank you in advance.
I think the most effective thing would be to create a new thread and call it,
The Messagebox is blocking because its on the same thread if you will create and start a new thread it will work
_Time = TimeSpan.FromSeconds(60);
//Creating a new thread
Thread newMessage = new Thread(runThread);
_Timer = new DispatcherTimer(new TimeSpan(0, 0, 1),DispatcherPriority.Normal, delegate
{
O2_Timer.Text = _Time.ToString("c");
if (_Time == TimeSpan.FromSeconds(30))
{
//Starting the thread
newMessage.Start();
}
if (_Time == TimeSpan.Zero)
{
_Timer.Stop();
MessageBox.Show("timer done");
Sub_Depth.Text = null;
}
_Time = _Time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
_Timer.Start();
private static void runThread(){
//The thread function
MessageBox.Show("timer is at 30 seconds");
}
I want to run timer countdown (DispatchTimer) multiple times in a loop, one after another. I want to wait until one timer stops and then run another one.
I'm gonna try something like this:
public TimeSpan CurrentTimeSpan;
private void RunInterval()
{
for (int i = 0; i < 10; i++)
{
RunTimer(new TimeSpan(0, 0, 0, 30));
}
}
private void RunTimer(TimeSpan Timer)
{
DispatcherTimer timer1 = new DispatcherTimer();
timer1.Interval = new TimeSpan(0, 0, 0, 1);
CurrentTimeSpan = Timer;
timer1.Tick += Timer1OnTick;
}
private void Timer1OnTick(object sender, object o)
{
DispatcherTimer timer = (DispatcherTimer) sender;
CurrentTimeSpan = CurrentTimeSpan.Subtract(timer.Interval);
if (CurrentTimeSpan.TotalSeconds == 0)
{
timer.Stop();
}
}
My problem is that method RunInterval or RunTimer doesn't wait until timer will stop.
What can I do about it?
Maybe something like this?
private int hitCount = 0;
public TimeSpan CurrentTimeSpan;
private void RunInterval()
{
RunTimer(new TimeSpan(0, 0, 0, 30));
}
private void RunTimer(TimeSpan Timer)
{
DispatcherTimer timer1 = new DispatcherTimer();
timer1.Interval = new TimeSpan(0, 0, 0, 1);
CurrentTimeSpan = Timer;
timer1.Tick += Timer1OnTick;
}
private void Timer1OnTick(object sender, object o)
{
DispatcherTimer timer = (DispatcherTimer)sender;
if(hitCount == 10)
{
timer.Tick -= Timer1OnTick
}
CurrentTimeSpan = CurrentTimeSpan.Subtract(timer.Interval);
if (CurrentTimeSpan.TotalSeconds == 0)
{
timer.Stop();
}
}
Instead of looping to create the timers just keep track in the event how many times it's been hit and then unhook the event once that target has been achieved.