I'm trying to make a function run every 200 milliseconds so that it can show the time difference between when the program first started and right now. I tried threading with this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ComputerTimer
{
public partial class MainWindow : Window
{
private DateTime startTime, endTime;
private static System.Timers.Timer timer1;
private bool running = true;
public MainWindow()
{
InitializeComponent();
startTime = DateTime.Now;
//makes new timer with 200 milliseconds interval
timer1 = new System.Timers.Timer(200);
timer1.Elapsed += new ElapsedEventHandler(timer1_Tick);
timer1.Interval = 200;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
while (running)
{
endTime = DateTime.Now;
TimeSpan span = endTime - startTime; //gets difference between now and when the program was started
Title.Content = span.ToString().Substring(0, 8); //gets first 8 characters (taking out milliseconds)
}
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
//when button is pressed to stop timer
running = false;
}
}
}
But this just throws the exception 'InvalidOperationException' and says "Additional information: The calling thread cannot access this object because a different thread owns it." about line 48
Title.Content = span.ToString().Substring(0, 8); //gets first 8 characters (taking out milliseconds)
I'm quite confused what to do from here and have searched all over stack overflow looking for an answer but nothing seems to work. I have also tried DispatcherTimer but with no luck.
Edit: This is the answer which worked for me for anyone looking over this in the future
namespace ComputerTimer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private DateTime startTime, endTime;
private DispatcherTimer dtClockTime;
public MainWindow()
{
InitializeComponent();
startTime = DateTime.Now;
dtClockTime = new DispatcherTimer();
dtClockTime.Interval = new TimeSpan(0, 0, 0, 0, 200); //in days, Hour, Minutes, Seconds, millis
dtClockTime.Tick += dtClockTime_Tick;
dtClockTime.Start();
}
private void dtClockTime_Tick(object sender, EventArgs e)
{
endTime = DateTime.Now;
TimeSpan span = endTime - startTime; //gets difference between now and when the program was started
Title.Content = span.ToString().Substring(0, 8);
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
//when button is pressed to stop timer
dtClockTime.Stop();
}
}
}
You've created an endless loop in the timer Tick event, you shouldnt have a while(x) loop in there.
private void timer1_Tick(object sender, EventArgs e)
{
endTime = DateTime.Now;
TimeSpan span = endTime - startTime; //gets difference between now and when the program was started
Title.Content = span.ToString().Substring(0, 8); //gets first 8 characters (taking out milliseconds)
}
And your stop button should just disable the timer
private void btnStop_Click(object sender, RoutedEventArgs e)
{
timer1.Enabled = false;
}
Edit: It might be that you need to set the SynchronisingObject of the timer
timer1.SynchronisingObject = this;
Failing the above it looks like for a wpf application (sorry, I initially missed the wpf tag) you should be using a DispatcherTimer in place of System.Timers.Timer.
The setup is much the same as your existing code, it just uses a different type of timer which raises the tick event on the correct (UI) thread.
As an aside, there is no need to string mash a DateTime object, there are methods for being able to format a timespan
Title.Content = span.ToString("mm:ss.ffff");
Only add SynchronisingObject parameter for your timer.
Like this:
timer1.SynchronisingObject = this;
Related
Dispose isn't working in my code for some reason. When i hit the reset button, and then start again, it won't start the timer over. I've tried disabling and reenablinig enabled(), but it still didn't work.
Here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class StopWatch : Form
{
bool reSet = false;
bool stopped = true;
public StopWatch()
{
InitializeComponent();
}
private void startStop_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
if (stopped == true)
{
timer1.Start();
stopped = false;
}
else
{
timer1.Stop();
stopped = true;
}
}
private void reset_Click(object sender, EventArgs e)
{
timer1.Dispose();
txtBox.Text = "";
reSet = true;
stopped = true;
}
int i = 0;
private void timer1_Tick(object sender, EventArgs e)
{
txtBox.Text = i.ToString();
i++;
}
}
}
Forget the timer for now, just make a stopwatch:
DateTime startTime = DateTime.MinValue; //it's reset
StartButton_Click(...){
startTime = DateTime.Now;
}
StopButton_Click(...){
MessageBox.Show("counted secs: " + (DateTime.Now - startTime).TotalSeconds);
}
That's a stopwatch
Now let's make it look like it runs. Add a label to the Form. Add a timer to the form, set it's interval to 100, enable it and put a tick event:
Timer_Tick(...){
StopWatchLabel.Text = startTime == DateTime.MinValue ? "00:00:00.000" : (DateTime.Now - startTime).ToString();
}
Now you can get into the minutiae of adding a reset button (set startTime to MinValue) starting and stopping the timer (no point updating a label to 00:00 ten times a second, but no harm in it either) but hopefully this proves that the timer is not (and should not) be part of the stopwatch function of measuring the passage of time. The timer doesn't need messing with/disposing etc. It's purely to update a label with the period that has passed since your start time
I have a problem I made a new form, with background img, and all I need and its working like I wanted, but I also need to auto close it after 5 or 10 seconds.
I searched on google all day ... but no tutorial was good.
I use Visual Studio 2013.
Can you boys help me please...
I'm desperate right now... its almost 10 hours since I'm trying.
You are my last hope.
Thanks
this.close() dosen't did it, or I made it wrong but i doubt that.
Application.Exit fail
timers give errors...
//form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Cerum_HS
{
public partial class CERUM_HS : Form
{
public CERUM_HS()
{
InitializeComponent();
Rectangle r = Screen.PrimaryScreen.WorkingArea;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - this.Width, Screen.PrimaryScreen.WorkingArea.Height - this.Height);
}
}
}
//main.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Timers;
//using System.Windows.Forms;
namespace Cerum_HS
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
private static System.Timers.Timer aTimer;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new CERUM_HS());
aTimer = new System.Timers.Timer();
aTimer.Interval = 10;
aTimer = new System.Timers.Timer(10);
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = false;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
//Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
Application.Exit();
//this.close();
}
}
}
Since my comment seemed to help, I thought I write it down as an answer.
public partial class CERUM_HS :
{
// here is the timer for the automatic closing
private static System.Timers.Timer aTimer;
public CERUM_HS()
{
InitializeComponent();
Rectangle r = Screen.PrimaryScreen.WorkingArea;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - this.Width, Screen.PrimaryScreen.WorkingArea.Height - this.Height);
}
private void Form_Load(object sender, System.EventArgs e)
{
// start here the timer when the form is loaded
aTimer = new System.Timers.Timer();
aTimer.Interval = 10;
aTimer = new System.Timers.Timer(10);
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = false;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
// Close the Application when this event is fired
Application.Exit();
}
}
Bogdan please comment if this implementation is how it worked for you in the end.
I would put a PictureBox and timer on your form (set to 5000 ms), click on the Tick event, and use this code:
namespace Image
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// set picture box to image of interest
// size and position form appropriately
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
this.Close();
}
}
}
I'm new to C# and I'm trying to make a custom chronometer that is composed of two labels (label1 and label2) that display time strings (time and time0/time1) and one button (pause/play) that changes its text from pause to play and viceversa on each click. Label1 shows time that is a string var maked by datetime.now (hhmmss), label2 shows time0 and after clicking on the button "pause" and again on "play" it will shows time1 (time 1 is calculated by the formula below).
It does the following:
get system datetime.now (hhmmss), saves it in time string and shows it in label1
pushing the button pause, saves the value of time in another string time0 and shows it stopped in label2
pushing the button play, starts the time of label2 (time1) that's not synchronized with the time of label1
To calculate time1 I would like to use this formula:
time1 = DateTime.Now - ((difference between DateTime.Now and time0) - 1 second)
I'm stucked on the 3rd point because I don't know how to do the time difference between two strings and use the new time time1 as text for label2 and next clicks.
This is my actual code, any help to complete it is appreciate, thank you.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//time0
public int hh = 0;
public int mm = 0;
public int ss = 0;
//time
public string time = "";
public string time0 = "";
public bool IsPause = true;
public Timer t = new Timer();
public Form1()
{
InitializeComponent();
}
private void label1_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
//timer interval
t.Interval = 1000; //in millisecondi
t.Tick += new EventHandler(this.t_Tick);
//start timer form loads
t.Start(); //questo userĂ il metodo t_Tick()
}
//timer eventhandler
private void t_Tick(object sender, EventArgs e)
{
//get current time
hh = DateTime.Now.Hour;
mm = DateTime.Now.Minute;
ss = DateTime.Now.Second;
//padding leading zero
if(hh < 10)
{
time += "0" + hh;
}
else
{
time += hh;
}
time += ":";
if(mm < 10)
{
time += "0" + mm;
}
else
{
time += mm;
}
time += ":";
if (ss < 10)
{
time += "0" + ss;
}
else
{
time += ss;
}
//update labels
label1.Text = time;
if (IsPause == false) label2.Text = time0;
else label2.Text = time;
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "pause")
{
IsPause = false;
button1.Text = "play";
time0 = label1.Text;
}
else
{
IsPause = true;
button1.Text = "pause";
}
}
}
}
It sounds as if you are best saving the time in the controls as well as the time as a string. The Tag property is there for that purpose. See https://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag%28v=vs.110%29.aspx
So, for example, if you set the DateTime you are using into label2.Tag to the same time as you format it as text in label2.Text then you can refer to it as a DateTime. Then when you need to calculate from it you can use
DateTime.Subtract - see https://msdn.microsoft.com/en-us/library/8ysw4sby%28v=vs.110%29.aspx
to determine the elapsed time.
So, to refer this to your code, wherever you have code like this, where time is the string you have created from a DateTime instance:
label1.Text = time;
you also need to set the time like this (DateTime.Now is an example, you should chose whatever you used to format the time string):
label1.Tag = DateTime.Now
Then later, when you want to know the time in label1, do this:
DateTime t = (DateTime)label1.Tag
I have a metronome project set up. I have a tap button which should check the tempo of your beat and average it out. Every bit of math works properly because I checked it with a calculator. 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.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
namespace Metronome
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer3_Tick(object sender, EventArgs e)
{
// Convert tempo to timer1.Tick (miliseconds between each beat)
timer1.Interval = Convert.ToInt32(60000 / numericUpDown1.Value);
}
private void button1_Click(object sender, EventArgs e)
{
// Play / Pause button
if (button1.Text == "Go!") { timer1.Enabled = true; button1.Text = "Stop!"; }
else if (button1.Text == "Stop!") { timer1.Enabled = false; button1.Text = "Go!"; }
}
private void timer1_Tick(object sender, EventArgs e)
{
// The 'ding' sound for the metronome
SystemSounds.Beep.Play();
}
private void button2_Click(object sender, EventArgs e)
{
// Set the tempo to be the average of the convertion from miliseconds between 2 beats and the current tempo
if (timer2.Enabled) { numericUpDown1.Value = ((60000 / Tap) + numericUpDown1.Value) / 2; Tap = 0; }
else timer2.Enabled = true;
}
int Tap = 0;
private void timer2_Tick(object sender, EventArgs e)
{
// Get the amount of miliseconds between each beat
Tap++;
}
private void button3_Click(object sender, EventArgs e)
{
// Reset the tap timer
timer2.Enabled = false;
Tap = 0;
}
}
}
The problem is in timer2_Tick, because it should add 1 to Tap every milisecond, instead, when I tried it it goes to a tiny number like 20 or 30. How can I fix this?
There is a really good article I always rely on when selecting which timer to use:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
I would suggest using one of the threaded options. Specifically, the article says of the the windows forms timer (System.Windows.Forms.Timer):
If you're looking for a metronome, you've come to the wrong place.
If you only need to check the amount of time passed between button taps, use a StopWatch. It gives you a high precision timing mechanism. There is no need for you to count milliseconds yourself.
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