Show a running timer in a WPF window - c#

I need to show a running timer on the window along with information of a test, such as ID, test name, status, start time, end time, etc.
I really wish that I could have a timer control on the page that tells the user that how long the test has been running.
How would one add a running timer on the page?
In addition, if this is possible, I wish my timer could start from some specific time instead of 00:00:00. The reason I need this is because the user can open this page when the test has been running for a while, and the elapsed time shown on the timer should be (current_time - start_time) and start from here.
If the test start at: 7:00 AM and the user opens the page at 7:05AM and the test is still running, the timer should start from 00:05:00.

Here is a very basic example I threw together.
using System.Windows.Threading;
namespace BasicTimer
{
public partial class MainWindow : Window
{
DispatcherTimer t;
DateTime start;
public MainWindow()
{
InitializeComponent();
t = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 50), DispatcherPriority.Background,
t_Tick, Dispatcher.CurrentDispatcher); t.IsEnabled = true;
start = DateTime.Now;
}
private void t_Tick(object sender, EventArgs e)
{
TimerDisplay.Text = Convert.ToString(DateTime.Now - start);
}
MainWindow XAML
<Window x:Class="BasicTimer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="100" Width="200">
<Grid>
<TextBlock x:Name="TimerDisplay" HorizontalAlignment="Left"/>
</Grid>
</Window>

Here is how I achieved this.
Stopwatch watch = new Stopwatch();
private void StartTimer()
{
new Thread(() =>
{
watch.Restart();
while (watch.IsRunning)
{
Dispatcher.Invoke(() =>
{
timeText.Text = Math.Round(watch.Elapsed.TotalSeconds, 2).ToString() + "s";
});
}
}).Start();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//i had to start and stop the timer inside a thread, i was having issues without doing so
new Thread(() =>
{
StartTimer();
//I was calling an api here
Dispatcher.Invoke(() =>
{
messageText.Text = response.message;
});
watch.Stop();
}).Start();
}

Related

The time is displayed every 5ms, and the difference between displaying "fff" is not 5, it How is it calculated? [duplicate]

This question already has answers here:
WPF Timer problem... Cannot get correct millisecond tick
(3 answers)
Closed last month.
I want to display the time every 5ms, and 'fff' is used in wpf to represent ms.
Why is the fff difference in the code of new TimeSpan(0, 0, 0, 0, 5); displayed result not 5? How is it calculated?
Xaml:
<Grid>
<ListBox Height="140" HorizontalAlignment="Left" Margin="18,31,0,0"
Name="listBox1" VerticalAlignment="Top" Width="308" />
<Button x:Name="btn" Click="btn_Click" Height="50" Content=" stop"/>
</Grid>
Codebehind:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
DispatcherTimer timer = new DispatcherTimer();
public bool What { get; set; }
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MessageBox.Show("Start");
timer.Interval = new TimeSpan(0, 0, 0, 0, 5);
timer.Tick += new EventHandler(dispatcherTimer_Tick);
timer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
listBox1.Items.Add(DateTime.Now.Hour.ToString() + ":" +
DateTime.Now.Minute.ToString() + ":" + DateTime.Now.Second.ToString() + ":"+DateTime.Now.Millisecond.ToString());
CommandManager.InvalidateRequerySuggested();
listBox1.Items.MoveCurrentToLast();
listBox1.SelectedItem = listBox1.Items.CurrentItem;
listBox1.ScrollIntoView(listBox1.Items.CurrentItem);
}
private void btn_Click(object sender, RoutedEventArgs e)
{
timer.Stop();
}
}
}
The result:
Update :
public MainWindow()
{
InitializeComponent();
DataContext = this;
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task timerTask = RunPeriodically(sendRequest, TimeSpan.FromMilliseconds(num), tokenSource.Token);
}
private void sendRequest()
{
k++;
datas.Add(DateTime.Now );
}
async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token)
{
while (k<7)
{
action();
await Task.Delay(interval, token);
}
}
When you set the Interval of the timer to 5 milliseconds, the timer will not be executed every 5 milliseconds. The timer doesn't have that high resolution.
From the documentation:
Timers are not guaranteed to execute exactly when the time interval
occurs, but they are guaranteed to not execute before the time
interval occurs. This is because DispatcherTimer operations are placed
on the Dispatcher queue like other operations. When the
DispatcherTimer operation executes is dependent on the other jobs in
the queue and their priorities.
Task.Delay also uses a timer internally. The resolution is again not high enough for 5ms intervals.
From the documentation:
This method depends on the system clock. This means that the time
delay will approximately equal the resolution of the system clock if
the millisecondsDelay argument is less than the resolution of the
system clock, which is approximately 15 milliseconds on Windows
systems.

After 30 seconds the info window jumps to logIn window in WPF

when the application runs, it displays an info message with a timer, the timer shows the user, that application is in run and not being frozen. after the timer ends, the app jumps automatically to the next page! how can write the async method with wait 30 seconds? any idea?
XML
<Grid>
<TextBlock TextWrapping="Wrap"
Text="Thanks alot for your using this app. this is a text application."
FontSize="30"/>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<TextBlock Name="tbTime" FontSize="30"/>
</StackPanel>
</Grid>
Code C#
public partial class InfoScreen : Window
{
DispatcherTimer timer;
TimeSpan time;
public InfoScreen()
{
InitializeComponent();
JumpToLogIn();
time = TimeSpan.FromSeconds(30);
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);
timer.Start();
}
private async void JumpToLogIn()
{
var infopage = new InfoScreen();
infopage.Show();
this.Close();
}
}
If you mean you want the JumpToLogin() method to wait 30 seconds before executing, then you can try the following:
private async void JumpToLogIn()
{
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(30));
var infopage = new InfoScreen();
infopage.Show();
this.Close();
}

WPF Dispatch Timer Starting at 0

I am creating a little quiz and need to test how fast someone will do it. I would like the timer to start at 0 and then to count up from there so that the user can see how fast they are completing this said quiz.
I have the following code:
using System.Windows.Threading;
DispatcherTimer QuizTimer;
QuizTimer = new DispatcherTimer();
QuizTimer.Interval = new TimeSpan(0, 0, 1);
QuizTimer.Tick += new EventHandler(QuizTimer_Tick);
private void QuizTimer_Tick(object sender, EventArgs e)
{
lblQuizTimer.Content = DateTime.Now.ToString("mm:ss");
}
After searching the internet I haven't found any examples of where the dispatch timer is set to 0 and counts up. I understand that DateTime.Now means it's using the time that it is on computer right now and counting from there, but there are no other options that I have been able to see.
Just store the DateTime when the timer is started:
private DateTime startTime;
...
startTime = DateTime.Now;
QuizTimer.Start();
and subtract it from the current time to get a TimeSpan:
private void QuizTimer_Tick(object sender, EventArgs e)
{
lblQuizTimer.Content = (DateTime.Now - startTime).ToString(#"mm\:ss");
}
As a note, in WPF you would usually use a TextBlock instead of a Label to display some text:
tbQuizTimer.Text = (DateTime.Now - startTime).ToString(#"mm\:ss");
private readonly Stopwatch stopwatch = new Stopwatch();
...
stopwatch.Start();
private void QuizTimer_Tick(object sender, EventArgs e)
{
lblQuizTimer.Content = stopwatch.Elapsed.ToString(#"mm\:ss");
}
The Stopwatch class allows you to Stop and Start and that would make this scenario a bit easier.

WPF InitializeComponent doesn't seem to work with DispatcherTimer

I am new to C# and also to WPF, I am trying to understand how DispatcherTimer works with GUI (WPF). I want to make my application run a function every 2 seconds but still using the app itself, when I try the following code, the timer starts but I can't use the following Buttons (logout and exit), it's like the app freezes.
public MainLoggedWindow()
{
Globals.mainLoggedWindow = this;
InitializeComponent();
DispatcherTimer dt = new DispatcherTimer();
dt.Tick += new EventHandler(dtTiker);
dt.Interval = new TimeSpan(0, 0, 1);
dt.Start();
}
private void exit_button_Click(object sender, RoutedEventArgs e)
{
logout_button_Click(sender, e);
Environment.Exit(-1);
}
private void logout_button_Click(object sender, RoutedEventArgs e)
{
Globals.LOGGED_IN_USER.logout();
this.Hide();
Globals.mainWindow.Show();
}
private int increment = 0;
private void dtTiker(object sender,EventArgs e)
{
increment++;
Time.Content = increment.ToString();
}
DispatcherTimer runs on the UI thread. It means that when the DispatcherTimer invokes its Tick method the UI thread becomes busy handling that, and it doesn't have time to handle other UI input like button clicks, so the window freezes.
What you could do is increase the interval time for your DispatcherTimer - your question desription says that it's once every two seconds, but your initialisation logic has it every one second: dt.Interval = new TimeSpan(0, 0, 1);

WPF Progressbar Stops after a Few Bars

In my WPF application i have to show a progressbar progress with in a timer tick event, which i am writing as below,
System.Windows.Forms.Timer timer;
public MainWindow()
{
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
}
load event as below
private void Window_Loaded(object sender, RoutedEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Value = DateTime.Now.Second;
progressBar1.Maximum = 700;
timer.Start();
}
And at last in tick event,
private void timer_Tick(object sender, EventArgs e)
{
Duration duration = new Duration(TimeSpan.FromSeconds(20));
//progress bar animation
System.Windows.Media.Animation.DoubleAnimation doubleanimation = new System.Windows.Media.Animation.DoubleAnimation(200.0, duration);
progressBar1.BeginAnimation(ProgressBar.ValueProperty, doubleanimation);
}
When the program's progressbar shows the progress for two-three bars and then it stops increment. Later there is no effect in the progress at all.
Why?
Since your ProgressBar doesn't relate to any particular behavior, it looks like a job for an indeterminate bar.
This other SO question provides some insight about it. In short, it's a XAML one-liner:
<!-- MinVal, MaxVal, Height needed for this to work -->
<ProgressBar x:Name="progressBar1" Margin="5" IsIndeterminate="True"
MinimumValue="0" MaximumValue="700" value="0" Height="20"/>
Then in code, you go like this:
progressBar1.IsIndeterminate = true; // start animation
progressBar1.IsIndeterminate = false; // stop animation
In my WPF application I have ... System.Windows.Forms.Timer timer;
That is the wrong type of timer. Use a DispatcherTimer instead.
When i execute my program progressbar shows the progress for two-three bars and then it stops
This surprises me, I wouldn't have expected it to work at all. This means you may have other problems too, like blocking the main (dispatcher) thread.
You are only setting the Value once, in the Loaded event:
progressBar1.Value = DateTime.Now.Second;
There is no change to progressBar1.Value in the Tick event. So it figures that it stops moving.
Use DispatcherTimer instead of Timer (Forms object), and use Value property of ProgressBar.
Try this:
MainWindows.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="55" Width="261">
<Grid>
<ProgressBar Name="pb" Maximum="60" />
</Grid>
</Window>
MainWindows.xaml.cs:
using System.Windows;
using System.Windows.Threading;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
private DispatcherTimer timer;
public MainWindow()
{
InitializeComponent();
this.timer = new DispatcherTimer();
this.timer.Tick += timer_Tick;
this.timer.Interval = new System.TimeSpan(0, 0, 1);
this.timer.Start();
}
private void timer_Tick(object sender, System.EventArgs e)
{
this.pb.Value = System.DateTime.Now.Second % 100;
}
}
}
You can change the behaviour of the progress bar by changing the Value property (don't forget defining the Maximum property in the xaml).
I found this (WPF Multithreading: Using the BackgroundWorker and Reporting the Progress to the UI. link) to contain a great solution for my needs, albeit with a dialog box.
The one thing I found very useful was that the worker thread couldn't access the MainWindow's controls (in its own method). However, when using a delegate inside the main windows event handler, it was possible.
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
pd.Close();
// Get a result from the asynchronous worker
T t = (t)args.Result
this.ExampleControl.Text = t.BlaBla;
};

Categories

Resources