DateTime class as Stopwatch - c#

my school project is to make a c# aplication with one button start/stop that starts to count the time and by clicking again stops count the time.
When i use this 3 lines
txtVrijeme.Text = Convert.ToString(sada.AddSeconds(i).ToString("HH:mm:ss"));
Thread.Sleep(1000);
i++;
without loop (while,for,goto etc.) in forms apk. it works (display 00:00:00, and if i click again 00:00:01) but when I use loop it does not display anything. Why ? btw. console aplication works with this code without any problem(loop in console)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BradičićManuelŠtoperica
{
public partial class Form1 : Form
{
DateTime sada = new DateTime(2009, 6, 22, 0, 0, 0);
int i = 0;
bool x = true;
public Form1()
{
InitializeComponent();
}
void execute(bool y)
{
while (y == true)
{
txtVrijeme.Text = Convert.ToString(sada.AddSeconds(i).ToString("HH:mm:ss"));
Thread.Sleep(1000);
i++;
}
}
private void btnStartStop_Click(object sender, EventArgs e)
{
if (x == false)
x = true;
else
x = false;
execute(x);
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}
excuse my English :)

Changing a textbox property does not directly draw anything to the screen.
Say it again:
Changing a textbox property does not directly draw anything to the screen.
What does happen is the Textbox control will invalidate it's graphics area, which will cause a WM_PAINT message to be generated.
The program needs to process this WM_PAINT message before the screen can be updated. The thread that receives and processes your paint events is the same thread where your execute() method is running. It's also the same thread that would handle your btnStartStop_Click() method.
Unfortunately, the execute() method never finishes. It never lets execution on that thread fall back to your program's main message loop, so your program can't repaint the textbox and it can't handle the button click that might finally let the execute() method stop. Even when it pauses, it puts the whole thread to sleep.
What you need to do instead is use a Timer component, and handle the Timer's Tick event.
Additionally, timer events are not perfectly precise. The slight variance for each Tick event can add up over time, so rather than incrementing the current value for each event your program should remember the start time and compute the difference from the current time.

As others have said, part of the problem is that you're trying to execute a hard loop inside the same thread that's responsible for updating the UI. Instead of using a loop like this, it's better to use a Timer, because the timer will run in a different thread so your UI will remain responsive.
The Timer has an Interval property that defines how often it executes a task. In our case it will be updating the textbox text. I've set this value to 100 milliseconds in the code below. The timer also has a Tick event that will execute every time the Interval elapses. Inside this event is where we put the code to update the textbox text.
We should should use a Stopwatch to measure elapsed time, because that's what it was built for. The DateTime object is great for holding dates, but it's not as accurate for measuring time.
A stopwatch has a Start and a Stop method that we can call from the button click event, so inside that event all we have to do is first check if the stopwatch is running. If it is, then we Stop it. If it isn't, then we Start it.
Putting these ideas together, your code could look something like this:
// At the top of your file, you'll need this to access the Timer:
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static Stopwatch stopwatch = new Stopwatch();
private static readonly Timer Timer = new Timer { Interval = 100 };
private void Form1_Load(object sender, EventArgs e)
{
btnStartStop.Text = "Start";
txtVrijeme.Text = stopwatch.Elapsed.ToString("hh\\:mm\\:ss\\.ff");
Timer.Tick += Timer_Tick; // This hooks up an event handler for the Tick event
}
// This code executes every {Timer.Interval} millisecond when the timer is running
private void Timer_Tick(object sender, EventArgs e)
{
txtVrijeme.Text = stopwatch.Elapsed.ToString("hh\\:mm\\:ss\\.ff");
}
// This method handles the button click. It changes the button text and starts
// or stops the stopwatch, depending on whether the stopwatch is running
private void btnStartStop_Click(object sender, EventArgs e)
{
if (stopwatch.IsRunning)
{
stopwatch.Stop();
Timer.Stop();
btnStartStop.Text = "Start";
}
else
{
Timer.Start();
stopwatch.Start();
btnStartStop.Text = "Stop";
}
}
}

Don't use DateTime for this. Instead, create a Stopwatch (in the System.Diagnostics namespace). You won't need to increment it yourself - just start it when the button is clicked, then evaluate its Elapsed property to get the duration elapsed (which is a TimeSpan type).
Yes, you'll also want a timer to periodically update the display. That timer can fire as often as you like, and can be imprecise - because it's not responsible for updating the stopwatch, just for writing the current value of the stopwatch to the display.
In summary:
DateTime is for representing a date and time of day.
DateTime.Now, DateTime.UtcNow, etc. give a mechanism to get the current date and time of day.
TimeSpan is for representing durations of elapsed time.
Stopwatch gives a mechanism for measuring elapsed time.
Separate the updating of the display from measurement of time. They are separate concerns.

Your project won't work because you never leave while.
You should try to use Timer.
Read about it here.
I think this video must help you.

Related

How can i start timer immediately in windows form?

I have a little problem. There is something like chess timer. When i press button, current timer stops and second starts, but after 1 second. How can i start second one immediately?
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1 {
public partial class Form1 : Form {
byte sec1;
byte sec2;
public Form1() {
InitializeComponent();
sec1 = 0;
sec2 = 0;
}
private void button1_Click(object sender , EventArgs e) {
timer1.Start();
timer2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
timer2.Start();
timer1.Stop();
}
private void timer1_Tick(object sender , EventArgs e) {
label1.Text = sec1.ToString();
sec1++;
}
private void timer2_Tick(object sender , EventArgs e) {
label2.Text = sec2.ToString();
sec2++;
}
}
}
Edit
I know your question is "how to start the timers immediately", but in your code they are starting immediately. When you call start the timer starts. I believe the effect you are seeing is related to the delay associated with the tick event, which from the description I am assuming is set to a 1 second interval. Since you have said that you are trying to simulate something similar to a chess timer (although in your case counting up as opposed to down), then using something like a stop watch which can start, stop and show elapsed time would be a closer model. Since there is a Stopwatch class that provides exactly this behavior, I think it would be easier to implement it using two of those and just have a single background thread that updates the UI as frequently as needed. You could even add an update call into each button push to ensure the text boxes are up to date.
===============================
Maybe instead of the timers you should use two instances of the Stopwatch class. This will remove the need for your two variables that you are using to keep track of the seconds as the Stopwatch class will be holding the elapsed time for each counter.
Then in your button methods you could just do this:
private Stopwatch sw1 = new Stopwatch();
private Stopwatch sw2 = new Stopwatch();
private void button1_Click(object sender , EventArgs e) {
sw1.Start();
sw2.Stop();
}
private void button2_Click(object sender , EventArgs e) {
sw2.Start();
sw1.Stop();
}
And then you can use a Background worker or some other background thread that runs and updates your text boxes with the elapsed time from the timers you just need to grab the elapsed time.
// This will give you the total number of seconds elapsed.
var timer1Seconds = Math.Floor(sw1.Elapsed.TotalSeconds);
Here is an example of how you can make this update the UI:
private bool _stop = false;
public Form1()
{
InitializeComponent();
Task.Run(() =>
{
while(!_stop)
{
UpdateElapsedTimes();
Thread.Sleep(1000);
}
}
}
private void UpdateElapsedTimes()
{
if (InvokeRequired)
{
Invoke(UpdateElapsedTimes());
return;
}
label1.Text = Math.Floor(sw1.Elapsed.TotalSeconds).ToString();
label2.Text = Math.Floor(sw2.Elapsed.TotalSeconds).ToString();
}
Note - in a production program I would not use a boolean as my loop checker, you would use an event handle, and probably a couple of event handles if you wanted to allow pausing the updates, this is just to show an idea of how to do it. You could invoke directly from the thread method and drop the InvokeRequired check, but I added that for additional safety and since it was there I skipped it in the loop.
The timer does start immediately. The problem is that you are not reporting fractions of seconds, so the display will show 0 until a full second has elapsed, which is accurate, technically.
If you want to show 1 immediately, just initialize your variables that way.
public Form1() {
InitializeComponent();
sec1 = 1;
sec2 = 1;
}

How to continually update a label with the current time?

I used the following line of code
int pp = DateTime.Now.Hour;
and it is ok. I wrote
label1.text=pp.tostring();
for verification and it works, but if I open my form at 19:59 (eg.) in label1 appears 19 and after one minute, when the clock is 08:00, the value in label1 is not changing and still appears 19, not 20.
After that, if I close the form and reopen it, the number in label1 is 20.
How can I modify the value from datetime.now.hour in real time, while the form is running?
thank you
Since you are using the "form" terminology, I'll assume Windows Forms, and the easiest way would be adding a Timer component, set a reasonable Interval (reasonable meaning how long is it the maximum you can afford to delay when the hour changes before the label changes... the higher the interval, the less CPU your process will occupy) on it, and on its Tick event, do your:
static void MyTimer_Tick(object sender, EventArgs e)
{
int pp = DateTime.Now.Hour;
label1.text=pp.tostring();
}
You need to implement a Timer, and have its Elapsed event update label1.text. Simply calling DateTime.Now.Hour is not enough, as that only updates it once. It does not set a recurring method to constantly update.
using System.Timers;
namespace Example {
static Timer _timer;
static void Main() {
_timer = new Timer(1000); // Update every 1 second.
_timer.Elapsed += UpdateMyLabel;
_timer.Start();
}
static void UpdateMyLabel(object sender, ElapsedEventArgs e) {
label1.Text = DateTime.Now.Hour;
}
}
I would deduce the Label class and use timer tick for updating the label. Just like in OOP ;)

How to make DispatcherTimer show time in a textbox and perform action when reaches a certain time in C#?

This is my second question on StackOverflow here. I posted my first question a while ago and got a working reply in no time, much impressed, much appreciated.
Anyways, so what I want to know is, how to get a DispatcherTimer to work and show time in a certain textbox and stop it when it reaches a certain time (let's say 60 seconds) and perform a function after 60 seconds.
What I'm basically using this for is :
Making a game, which has to stop after 60 seconds and show the scores or related stuff. So this requires me to show the time in a textbox and perform a function at 60 seconds or after that.
Here's more information :
Textbox is called "timerbox"
Here's the code I've tried :
DispatcherTimer dt = new DispatcherTimer();
private void TimerStart(object sender, RoutedEventArgs e)
{
dt.Interval = TimeSpan.FromSeconds(1);
dt.Tick += dt_Tick;
dt.Start();
}
int count = 0;
void dt_Tick(object sender, object e)
{
count = count + 1;
timerbox.Text = Convert.ToString(count);
}
It doesn't show the time in textbox, plus I don't know how to make it stop at certain point and perform a function.
Thank you for reaching here, please leave answers with full explanation as I'm a complete beginner :)
P.S. I'm using Windows Store App Development Environment in Visual Studio 2013.
And there's no "Timer" in it as there is in normal C# Environment.
AOA.
I am recently started learning c#. (interested in windows form application). Hope this help you.
if you just want to set timer for a curtain event.....
recommend you using timer ( in toolbox )......
follow steps, when you double click on timer1 VS will create a timer1_Tick function for you which will be called every timer you timer ticks.....
now what you want to do when timer1 icks write it in there....like this....
private void timer1_Tick(object sender, EventArgs e)
{
//enter your code here
}
now write timer1. and VS will display a list of avaliable function....
for example,
timer1.Interval = (60*1000); //enter time in milliseconds
now when you want to start the write......
timer1.Start();
and to stop timer at any timer call
timer1.Stop();
if you want to repeat timer just write timer1.start() in that tick function.....
plus, to set textbox text equal to timer1 time use something like
textBox1.Text = Convert.ToString(timer1.Interval);
Click here for more information on timer class
hope this help you,
in case of any confusion, just comment,.....
The normal flow of a DispatcherTimer would look like this:
First Set up your new Object, set up the a new EventHandler that will run your desired code each Tick and Set the Timespan for the desired Tick Interval.
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Tick += new EventHandler<object>(timer_Tick);
timer.Interval = TimeSpan.FromMilliseconds(bpm);
}
Set The Timer_Tick Envent
async Void timer_Tick(object Sender, object e)
{
await this.Dispatcher.RunAsync(Windows.UI.core.CoreDispatcherPriority.High, () =>
{
//Run the Code
textBox1.text = timer.interval.TotalMilliseconds.ToString();
});
You have to have a trigger to Start the Dispatcher(and to stop if you need to), for example a button
private void StartButton_Click()
{
timer.Start();
}
This example was done using The new windows 10 Universal App platform within VS2015, but I think it should look about the same in a normal windows 8 App

Cycle method in Visual C# and .NET 4.0

I have created a new Windows Forms Application with C# and .NET 4.0, and I have a function that must be called automatically every 60th of a second. My problem, is that I do not know where to call this function. .NET forms don't appear to have a built-in on-update event.
How would I go about getting this function called every 60th of a second?
Sorry if it is a beginner question.
You could set up a Timer to invoke a callback every 16 ms (which is 1/60 sec).
Important point as mentioned by #spender: If you are requiring very precise timing on this, eg exactly every 1/60 sec precision, you will not be satisfied with this solution. Windows does not natively do high-resolution timing in that vein very well. Props to #spender for the mention.
Here's a sample class with a rough outline of how it might look in a plain vanilla class, so you'd need to adapt it to your form:
You might also want to call this on a background thread, but if you're new to WinForms, we'll start in small chunks. Let's try the timer first, then go from there.
class Demo{
System.Timers.Timer myTimer;
void InitializeTimer(){
myTimer = new Timer(16); // elaps every 1/60 sec , appx 16 ms.
myTimer.ElapsedEventHandler+=new ElapsedEventHandler(myTimerEventHandler); //define a handler
myTimer.Enabled=true; //enable the timer.
}
void myTimerEventHandler(object sender, ElapsedEventArgs e){
// do your thing here
}
}
EDIT: Extra demo code for background thread creation and Invoked-based GUI update
As noted in my comment below, this is not as polished as I would like it, but I think it illustrates the salient points. It defines a BackgroundWorker thread to move the thread invocations to the background; the thread callback checks for the need to call Invoke, and calls right back to itself across a delegate invocation to allow for the custom form update in the "else" block of the "if (InvokeRequired)" statement. In a nutshell, a background thread starts, and starts a timer; when the timer elapses, it calls the updater on the background thread, which checks to see if Invoke must be called, and if it is, performs the thread context switch back to the GUI thread through the recall to the method, which then performs the GUI update. Put your custom update code in that "else" block. I hope this helps!!!
public partial class Form1 : Form
{
delegate void FormUpdateDelegate(object sender, ElapsedEventArgs e);
public BackgroundWorker backgroundThread;
System.Timers.Timer foo;
Random colorgen = new Random();
public Form1()
{
InitializeComponent();
backgroundThread = new BackgroundWorker();
backgroundThread.DoWork+=new DoWorkEventHandler(backgroundThread_DoWork);
backgroundThread.RunWorkerAsync();
}
public void formUpdater(object sender, ElapsedEventArgs e)
{
if (InvokeRequired)
{
FormUpdateDelegate d = new FormUpdateDelegate(formUpdater);
Invoke(d, new object[] { sender, e });
}
else
{
// Do your form update here
this.label1.ForeColor = Color.FromArgb(colorgen.Next());
}
}
public void backgroundThread_DoWork(object sender, DoWorkEventArgs e)
{
foo = new System.Timers.Timer(16);
foo.Elapsed += new ElapsedEventHandler(formUpdater);
foo.Start();
}
}
I just setup this in a console application, and it runs fine every second:
var timer = new System.Timers.Timer(1000);
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(delegate(object sender, ElapsedEventArgs eventArgs)
{
Console.WriteLine("Elapsed");
});
It is a bad practice to hope on system timers when you need precision at least 20 times per second.
I would recommend to use cycles like
Timespan timePerFrame = Timespan.FromMilliseconds(16);
while (_isRunning)
{
Stopwatch timer = Stopwatch.StartNew()
// Action.
while (timer.ElapsedMilliseconds < timePerFrame) { /* Nothing? */ }
}
That will give you the full precision, if your system supports high-precision stopwatch. (.IsHighResolution field).

create checkbox checking sequence

Hello I am trying to program some checkboxes to become checked and unchecked in a specific sequence programmatically. I know it sounds dumb, but this is corresponding to some LED controls that I've already coded the check events for.
I want to check a checkbox to start this sequence and uncheck it to stop it. Currently the checking and unchecking of my D2 checkbox occurs fine, but the do while loop freezes the form so I can't actually uncheck the cycle box. I probably should not be using Thread.Sleep either. Any advice is appreciated.
private void cycleCheckBox_CheckedChanged(object sender, EventArgs e)
{
do
{
D2.Checked = true;
Thread.Sleep(1000);
D2.Checked = false;
Thread.Sleep(1000);
} while (cycleCheckBox.Checked);
}
The Thread.Sleep method will run on the UI thread if called directly in the checked event which is why the UI is freezing. Push the work into a System.Windows.Forms.Timer (assumption is this is a WinForms app):
Implements a timer that raises an event at user-defined intervals.
This timer is optimized for use in Windows Forms applications and must
be used in a window.
Example based on your question:
Timer _timer;
private void cycleCheckBox_CheckedChanged(object sender, EventArgs e)
{
if(_timer == null )
{
_timer = new Timer();
_timer.Interval = 1000; // 1 second
_timer.Tick += DoTimerWork;
}
if(cycleCheckBox.Checked)
{
_timer.Start();
}
else
{
_timer.Stop();
}
}
private void DoTimerWork(object obj, EventArgs args)
{
D2.Checked = !D2.Checked;
}
I don't know if this will work for you but what I would do is drag in a Timer Control at 1000 ms and use a method to figure out which checkbox should currently be checked by using an integer that loops to 0 at a certain point and gets incremented at each tick.

Categories