I have a button click event that start an operation :
private void Diagnose_Click(object sender, EventArgs e)
{
processfinish = false;
timer2.Enabled = true;
timerCount = 0;
count = 0;
countBack = 5;
CreateZip.Enabled = false;
DriverVerifier.Enabled = false;
Diagnose.Enabled = false;
Diagnose.Text = "PROCESSING PLEASE WAIT";
if (this.backgroundWorker1.IsBusy == false)
{
this.backgroundWorker1.RunWorkerAsync();
}
Logger.Write("***** OPERATION STARTED *****");
}
And the completed event of the backgroundworker :
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
processfinish = true;
Logger.Write("***** OPERATION ENDED *****");
}
And the timer1 tick event that start to work when its getting to the completed event:
private void timer1_Tick(object sender, EventArgs e)
{
count++;
Diagnose.Text = "PROCESS HAS FINISHED" + " " + countBack--;
if (count == 6)
{
Diagnose.Text = "COLLECT INFORMATION";
Diagnose.Enabled = true;
CreateZip.Enabled = true;
ViewLogFile.Enabled = true;
DriverVerifier.Enabled = true;
timer1.Enabled = false;
}
}
I want in my Logger text file to see something like:
Logger.Write("Operation Time Was: " + timepassed);
And timepassed will show minutes and second for example:
Operation Times Was: 05:21
Just use a StopWatch. Start() it to begin timing, Stop() it when you are done, and then get the Elapsed time and format it.
The simplest way (not the best since it isn't thread safe at all, so it won't work if you have 2 operations working at the same time)
Declare a private variable:
DateTime _start;
Then in your Diagnose_Click method, assign a value to it:
_start = DateTime.Now;
And in your backgroundWorker1_RunWorkerCompleted you can have the time elapsed like that:
TimeSpan elapsed = DateTime.Now - _start;
And you can write it directly in your log file using something like:
Logger.Write("Operation time was: " + elapsed.Minutes + "mn " + elapsed.Seconds + "s");
// Create new stopwatch
Stopwatch stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
// Do something
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(1);
}
// Stop timing
stopwatch.Stop();
// Write result
Console.WriteLine("Time elapsed: {0}",
stopwatch.Elapsed);
You can do
DateTime startTime = DateTime.Now;
Then after you are done processing do
DateTime endTime = DateTime.Now;
//This will give you something like 2hrs 15min or 15 days 11 hours 10 min ect
TimeSpan timePassed = endTime.Subtract(startTime);
Here is the MSDN Documentation http://msdn.microsoft.com/en-us/library/8ysw4sby.aspx
The advantage to using this method (other than it specifically uses DateTime like you specified above) is that there is no timer running. You are not using any resources really here. You just grab the DateTime at the start of your process and at the end. Then subtract them to get the difference. To easy.
Related
Soo I am making a stopwatch program, and I run into a little problem while making it stop and start.
This is the situation — I press "StartButton" and then I press "StopButton", but after pressing "StartButton" again, then it starts counting from the time it already counted.
The Timer function:
int i = 0;
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan time = TimeSpan.FromSeconds(i);
textBox1.Text = time.ToString(#"hh\:mm\:ss");
i++;
}
The StopButton function:
private void button4_Click(object sender, EventArgs e)
{
button3.Visible = true;
button4.Visible = false;
timer1.Stop();
timer1.Enabled = false;
textBox1.Text = "00:00:00";
}
The StartButton function:
private void button3_Click(object sender, EventArgs e)
{
button4.Visible = true;
button3.Visible = false;
timer1.Enabled = false;
timer1.Start();
textBox1.Text = "00:00:00";
}
I've tried to just make the "textBox1" to write "00:00:00", but it does not work at all.
(PS I'm bad at C#).
I would also have added a field with a start value:
private DateTime _timeStart = DateTime.Now;
Starting / Restarting:
_timeStart = DateTime.Now;
timer1.Start();
Displaying:
TimeSpan time = (DateTime.Now - _timeStart).TotalSeconds;
textBox1.Text ...
And... If you need to Pause the timer.
I would also have added and used these fields for handling the Paused time:
private DateTime _timePauseStart = DateTime.Now;
private TimeSpan _timeSpanPaused;
Begin Paused:
timer1.Stop();
_timePauseStart = DateTime.Now;
End Paused:
_timeSpanPaused += DateTime.Now - _timePauseStart;
timer1.Start();
Displaying:
TimeSpan time = (DateTime.Now - _timeStart - timeSpanPaused).TotalSeconds;
textBox1.Text ...
I just understand your question. Timer start from 0 everytime you Stop and Start it.
Consider to use Stopwatch class. With Stopwatch you can always continue where it is paused.
In order to restart stopwatch, use
sw.Reset();
sw.Start();
or
sw.Restart();
To continue where you left, use
timer1.Stop();
timer1.Start();
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);
}
}
I want to write a simple stopwatch program, I can make it work with the following code
public Form1()
{
InitializeComponent();
}
System.Diagnostics.Stopwatch ss = new System.Diagnostics.Stopwatch { };
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
button1.Text = "Stop";
ss.Start();
timer1.Enabled = true;
}
else
{
button1.Text = "Start";
ss.Stop();
timer1.Enabled = false;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
int hrs = ss.Elapsed.Hours, mins = ss.Elapsed.Minutes, secs = ss.Elapsed.Seconds;
label1.Text = hrs + ":";
if (mins < 10)
label1.Text += "0" + mins + ":";
else
label1.Text += mins + ":";
if (secs < 10)
label1.Text += "0" + secs;
else
label1.Text += secs;
}
private void button2_Click(object sender, EventArgs e)
{
ss.Reset();
button1.Text= "Start";
timer1.Enabled = true;
}
Now I want to set a custom start time for this stopwatch, for example I want it not to begin count up from 0:00:00 but to start with 0:45:00
How can I do it, thank you.
Stopwatch does not have any methods or properties that would allow you to set a custom start time.
You can subclass Stopwatch and override ElapsedMilliseconds and ElapsedTicks to adjust for your start time offset.
public class MyStopwatch : Stopwatch
{
public TimeSpan StartOffset { get; private set; }
public MyStopwatch(TimeSpan startOffset)
{
StartOffset = startOffset;
}
public new long ElapsedMilliseconds
{
get
{
return base.ElapsedMilliseconds + (long)StartOffset.TotalMilliseconds;
}
}
public new long ElapsedTicks
{
get
{
return base.ElapsedTicks + StartOffset.Ticks;
}
}
}
Create a new instance of System.TimeSpan with the initial value of 45 minutes as per you example. Than add the value of the stopwatch to it TimeSpan.Add Method. Conveniently the Stopwatch.Elapsed is of type System.TimeSpan already.
Than use string formatter to print the formatted time into the label. I think one of the other answers already shows how to do that. Otherwise here are some good references on how to format a TimeSpan instance TimeSpan.ToString Method (String) or using a custom formatter.
var offsetTimeSpan = new System.TimeSpan(0,45,0).Add(ss.Elapsed)
additional SetOffset() method
additional initialization with offset;
overrides all of needed methods
have the same class name, so no need to change your project code
.
using System;
public class Stopwatch : System.Diagnostics.Stopwatch
{
TimeSpan _offset = new TimeSpan();
public Stopwatch()
{
}
public Stopwatch(TimeSpan offset)
{
_offset = offset;
}
public void SetOffset(TimeSpan offsetElapsedTimeSpan)
{
_offset = offsetElapsedTimeSpan;
}
public TimeSpan Elapsed
{
get{ return base.Elapsed + _offset; }
set{ _offset = value; }
}
public long ElapsedMilliseconds
{
get { return base.ElapsedMilliseconds + _offset.Milliseconds; }
}
public long ElapsedTicks
{
get { return base.ElapsedTicks + _offset.Ticks; }
}
}
You can't alter the start time, but you can modify it after the Stop() and no one is the wiser.
A quick Google search: http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.start(v=vs.90).aspx
A minor modification:
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
// Format and display the TimeSpan value.
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes + 45 , ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
}
}
Result:
RunTime 00:45:10.00
Press any key to continue . . .
A little more research on your part will help you immeasurably as a developer.
is the offset fixed or variable?
In either case, have it as some member variable or const for the class and just add it.
private TimeSpan offset = TimeSpan.FromSeconds(45);
Then just change your tick to include it:
var combined = ss.Elapsed + offset;
int hrs = combined.Hours, mins = combined.Minutes, secs = combined.Seconds;
I'm trying to create a Windows Form application that searches for a string and has three possible scenarios:
String 1 found - wait
String 2 found - stop
Else - Perform action and wait 1 minute
I am encountering my problem only on the times when it is expected to wait. When this happens, the newTimer_Tick starts to tick every second. I have tried disabling the timer when it ticks and a few other things but none appeared to work. Below is the code:
public void Action(string result)
{
if (result.Contains("string1"))
{
// Check again in 10 + x seconds
int n = new Random().Next(0, 5000);
int newtime = 10000 + n;
newTimer.Tick += new EventHandler(newTimer_Tick);
newTimer.Interval = newtime;
newTimer.Enabled = true;
}
else if (result.Contains("string2"))
{
// Turn off
newTimer.Enabled = false;
}
else
{
// Perform action and tick again in 1min + x seconds
action1();
int n = new Random().Next(0, 5000);
int newtime = 600000 + n;
newTimer.Tick += new EventHandler(newTimer_Tick);
newTimer.Interval = newtime;
newTimer.Enabled = true;
}
}
private void newTimer_Tick(object sender, EventArgs e)
{
Action( result );
}
What have I done wrong?
Each time the following line is called, an new instance of the event handler newTimerTick is added to the invocation list for the Tick event:
newTimer.Tick += new System.EventHandler(newTimer_Tick);
So every time the time tick goes off newTimerTick is going to be called multiple times, which is going to give you unexpected results.
Configure your event handler once only. In the constructor would be a sensible place.
Have you tried to stop the timer with the Timer.Stop method?
Btw: I don't think you need to reassign the Tick event from the newTimer unless you don't create a new Timer everytime.
I think what you were missing is that you have to stop your timer since you don't actually want it to keep for more than one interval. You seem to want to run it once, check on the result and then decide if you want to keep running it or not. Here's the code:
public void action(string result)
{
int n = new Random().Next(0, 5000);
Boolean blActivateTimer = true;
Timer timer = new Timer();
timer.Tick += timer_Tick;
if (!result.Contains("string1") && !result.Contains("string2"))
{
n += 600000;
action1();
}
else
{
if (result.Contains("string1"))
{
n += 10000;
}
else
{
blActivateTimer = false;
}
}
if (blActivateTimer)
{
timer.Start();
}
}
void action1()
{
}
void timer_Tick(object sender, EventArgs e)
{
Timer t = (Timer)sender;
t.Stop();
action(result);
}
I'm creating a countdown timer that allows the user to choose a valid time, and once the countdown reaches zero, it plays a sound.
I've instantiated a timer from the System.Timers namespace and set its Interval to 1 second. I convert the user-specified time to seconds, and decrement that value by 1 every time the Timer.Elapsed function hits. Once it reaches zero, that means the countdown has reached zero which means it's time to play the sound.
However, whenever it doesn't reach zero, I decrement the time value by 1 and I also want to increment the ProgressBar by using the progressbar.Increment function.
Unfortunately, whenever I do this, it gives me an exception having to do with multithreading issues. I know what is wrong, but I am not sure how to fix it. Do I need to start the timer.Elapsed function on a new thread?
The error is:
Cross-thread operation not valid: Control 'CountdownProgress' accessed
from a thread other than the thread it was created on.
Also, any tips on better programming habits are welcome as well.
Many thanks!
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
using System.Media;
using System.Diagnostics;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form_CDA : Form
{
public Form_CDA()
{
InitializeComponent();
}
private bool m_CountdownActive; // declare global variables and instantiate timer.
private bool m_Cancelled;
public decimal seconds;
public decimal minutes;
public decimal hours;
public decimal time;
public System.Timers.Timer timer = new System.Timers.Timer();
private void Form_CDA_Load(object sender, EventArgs e)
{
m_Cancelled = false;
timer.AutoReset = false;
timer.Interval = 0;
m_CountdownActive = false;
richTextBox1.Text = "Hello, please select an hour between 0 and 100, a minute between 0 and 59, and a second between 0 and 59. The countdown timer will play a sound when finished.";
btn_Cancel.Enabled = false;
seconds = 0;
minutes = 0;
hours = 0;
time = 0;
m_StatusBar.Text = "Program properly loaded, waiting for user input"; // initialize variables.
}
private void btn_SetCountdown_Click(object sender, EventArgs e)
{
seconds = numUpDown_Seconds.Value;
minutes = numUpDown_Minutes.Value;
hours = numUpDown_Hours.Value;
time = (hours * 3600) + (minutes * 60) + seconds; // calculate the total time in seconds.
if (time != 0) // if time is not zero, start timer and set up event handler timer.elapsed.
{
timer.Interval = 1000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
CountdownProgress.Maximum = (int)time;
CountdownProgress.Minimum = 0;
CountdownProgress.Value = 0;
}
else
{
m_StatusBar.Text = "Invalid selection of times. Try again.";
return;
}
DateTime dt = DateTime.Now;
dt.AddSeconds((double)time);
Label_Countdown.Text = "Finishing time: " + dt.ToString(); // display end time to user.
m_CountdownActive = true;
btn_Cancel.Enabled = true;
btn_SetCountdown.Enabled = false;
numUpDown_Hours.Enabled = false;
numUpDown_Minutes.Enabled = false;
numUpDown_Seconds.Enabled = false; // disable controls.
m_Cancelled = true;
m_StatusBar.Text = "Timer set to " + numUpDown_Hours.Value.ToString() + " hours, " + numUpDown_Minutes.Value.ToString() + " minutes, " + numUpDown_Seconds.Value.ToString() + " seconds.";
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (time == 0)
{
m_StatusBar.Text = "Countdown Finished";
SoundPlayer soundPlayer = new SoundPlayer(#"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
soundPlayer.Play(); // play sound.
timer.Stop();
return;
}
else
{
time = time - 1;
CountdownProgress.Increment(1); // exception occurs here; multithreading issues.
}
}
private void btn_Cancel_Click(object sender, EventArgs e)
{
// if user wishes to stop the countdown to start a new one.
m_Cancelled = true;
m_CountdownActive = false;
btn_SetCountdown.Enabled = true;
numUpDown_Seconds.Value = 0;
numUpDown_Minutes.Value = 0;
numUpDown_Hours.Value = 0;
numUpDown_Hours.Enabled = true;
numUpDown_Minutes.Enabled = true;
numUpDown_Seconds.Enabled = true;
btn_Cancel.Enabled = false;
m_StatusBar.Text = "Countdown cancelled";
}
}
}
A control can only be accessed within the thread it was created. Therefore use Invoke to execute the given code as a delegate on the main thread, where the control (progressbar) was created.
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (time == 0)
{
m_StatusBar.Text = "Countdown Finished";
SoundPlayer soundPlayer = new SoundPlayer(#"C:\Users\marupakuuu\Desktop\New stuff\doorbell.wav");
soundPlayer.Play(); // play sound.
timer.Stop();
return;
}
else
{
time = time - 1;
Invoke(new Action(() => CountdownProgress.Increment(1)));
}
}
You may want to read http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx