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;
}
Related
i want realize a simple application that in a specific and precise time, with webbrowser control, go to the webpage.
public partial class Form1 : Form
{
System.DateTime timeStart = new System.DateTime(2016, 05, 25, 19, 30, 00, 00);
TimeSpan sub;
bool timeExpires = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 100;
timer1.Start();
while(timeExpires)
{
webBrowser1.Navigate("https://www.google.it/");
}
}
private void timer1_Tick(object sender, EventArgs e)
{
System.DateTime Now = System.DateTime.Now;
sub = timeStart.Subtract(Now);
if ((int)sub.TotalSeconds == 0)
{
this.timer1.Stop();
MessageBox.Show("ok, Time is up!");
timeExpires = true;
}
else
{
textBox1.Text = sub.ToString();
}
}
}
after the timecount, when timer1.stop() is set, the messagebox is show.
But webbrowser don't run .
I know that i use a bool variable timeExpires is an "antiquated" method.
I have two question :
where is the best pratice or best way to "notify" at webbrowser or any other thing that countdown is finish and now is time to run.
where is problem with this approch(boolean variable)? how I can run with this approch even if isn't the best way?
Thanks so much
You main thread is blocked by the while loop, so the messages/events aren't being processed. That way, the value of timeExpires never changes inside the loop. To you understand, you can Application.DoEvents() to force the events to be processed but it might not be a good unless you really understand how this works and how evil it can be.
You should open the browser inside the Timer's Tick event (just like where you're calling MessageBox.Show()) but be carefully on doing too many things on tick event, if you statements take more time to run than the Timer's interval, the Tick event will run again and might mess up everything. So, to solve this, whatever you enter in the Tick event, pause the timer and start again where you're done.
private void timer1_Tick(object sender, EventArgs e) {
timer1.Stop(); // prevent event to fire again, until we get some stuff done
if(timeStart >= DateTime.Now) {
openBrowser();
} else {
timer1.Start();
textBox1.Text = sub.ToString();
}
}
So I want to perform some button clicks say every in 10 second, and here is my code:
using System;
using System.Timers;
public class Main : Form {
public Main() {
InitializeComponent();
// add timer to do button clicking every 10 seconds
double elapse = 10000;
System.Timers.Timer timer2 = new Time(elapse);
timer2.Elapsed += new ElapsedEventHandler(ResetEvent);
timer2.AutoReset = true;
timer2.Start();
}
private void ResetEvent(object source, ElapsedEventArgs e) {
try {
Refresh_Button.PerformClick();
Process_Button.PerformClick();
} catch { }
}
private void Refresh_Button_Click(object sender, EventArgs e) {
// some code
}
private void Process_Button_Click(object sender, EventArgs e) {
// some code
}
}
However, it doesn't work. Is there anything wrong with the code? How can I make it works?
The problem is accessing UI thread illegally in Elapsed event of System.Timers.Timer.
You are calling Refresh_Button.PerformClick(); in Elapsed event of timer that cause an cross thread exception that you are hiding it.
To access UI thtread and call PerformClick() method of Refresh_Button:
Refresh_Button.Invoke(new Action(() => { Refresh_Button.PerformClick(); }));
Also you can use System.Windows.Forms.Timer instead and handle Tick event and call Refresh_Button.PerformClick(); manually.
Note:
Don't hide exceptions. If you hide exceptions, such problems will hide and finding them will be really hard.
It's better to put the logic a method and instead of calling PerformClick, call that method.
If you don't need a different thread, System.Windows.Forms.Timer whould be enough.
I am working on a stopwatch, that i want to use in some sort of competition. I would like to start my stopwatch by clicking Button 1 in order that first wav file is played and after that stopwatch starts. But Stopwatch doesn't start. This is what I came up to till now.
Stopwatch sw = new Stopwatch();
private void button1_Click(object sender, EventArgs e)
{
new System.Threading.Thread(testMethod).Start();
}
private void testMethod(object obj)
{
System.Media.SoundPlayer sp = new System.Media.SoundPlayer(#"D:\...\something.wav");
sp.Play();
}
void OnSoundPlayOver(object sender, EventArgs e)
{
timer1.Start();
timer2.Start();
sw.Start();
}
If your requirements are:
Start button that plays a sound, then starts a timer that displays the elapsed time on the screen.
Stop button that stops any current timers, leaving the last value on the screen.
Implemented in Windows Forms.
The following code is a BASIC example of how to get the above requirements working. It leverages the PlaySync method of SoundPlayer, a BackgroundWorker (to update the value on the label to be the elapsed seconds) and a Stopwatch for actually recording the elapsed time. It is definitely not the BEST way to accomplish this, but it should provide a starting point for you.
An important thing to note is that you cannot update a Label from a thread that is different from the thread that created the label (typically the UI thread). So if you're trying to update the Text of a label from another thread you need to use the labels .Invoke method (see the ThreadSafeUpdateLabel method in the code below).
This code does not take into account the situation where someone spam clicks the Start button (it just plays the sound as many times as you click) and the UI freezes when you click the Start button for as long as it takes the sound to play. I'll leave fixing those issues to you as a natural extension of the code.
Anyway, onto the code:
private Stopwatch _timer = new Stopwatch();
private BackgroundWorker _worker;
private void btnStop_Click(object sender, EventArgs e)
{
CancelExistingBackgroundWorker();
_timer.Stop();
}
private void btnStart_Click(object sender, EventArgs e)
{
CancelExistingBackgroundWorker();
_timer.Reset();
UpdateLabel(0);
_worker = new BackgroundWorker() { WorkerSupportsCancellation = true };
_worker.DoWork += (a, b) =>
{
while (true)
{
if ((a as BackgroundWorker).CancellationPending) return;
ThreadSafeUpdateLabel();
Thread.Sleep(100);
}
};
var soundPlayer = new SoundPlayer("wavfile.wav");
soundPlayer.PlaySync();
_timer.Start();
_worker.RunWorkerAsync();
}
private void ThreadSafeUpdateLabel()
{
if (lblElapsed.InvokeRequired)
{
lblElapsed.Invoke(new Action(() => ThreadSafeUpdateLabel()));
}
else
{
UpdateLabel(_timer.Elapsed.TotalSeconds);
}
}
private void UpdateLabel(double seconds)
{
lblElapsed.Text = seconds.ToString();
}
private void CancelExistingBackgroundWorker()
{
if (_worker != null)
{
_worker.CancelAsync();
_worker.Dispose();
}
}
I have a timer of 1 second in C#, with a while sequence in it. My question is if the while sequence is not finished before 1 second, will the timer tick, and restart the while from the beginning?
The part of the code is below, and what it does is that it cycles through the selected objects and changes something. So, if there are a lot of objects selected and I need more than 1 second to change them, will they all be changed?
P.S. I actually want the loop to be broken; a large number of objects will be selected only by mistake, but I just want to be sure that I avoid this possibility. :)
private void timer1_Tick(object sender, EventArgs e)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
}
Yes, timer ticks can happen concurrently. This means that your timer must be thread-safe.
Except for the UI timer classes (WinForms/WPF). Their tick functions run on the UI thread. With DoEvents you can cause reentrancy even there which is another reason to avoid DoEvents.
From the name of the handler I assume you are using System.Windows.Forms.Timer which is single-threaded. That means the Tick event will fire after the previous one has ended. To break the loop, you will have to execute the code in another thread an use an exit condition.
This is how I usually do it:
private bool running;
private bool restart;
private void DoWork(object item)
{
running = true;
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext() && !restart)
{
//do your stuff
if (myEnum.Current != null) {....}
}
if(restart)
{
restart = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (running)
restart = true;
else
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
}
A workaround would be to disable the timer at the top of the while event, and re-enable it as you exit the while event.
The while loop will not be broken because the timer has ticked again. But in any case, your best bet would be to disable the timer at the beginning of the event handler, and re-enable it again at the end.
You could always try something similar to this instead, that way you void having multiple timers tick over and kick off processes. Written in Notepad so please excuse any massive spelling mistakes
private Timer _systemTimer = null;
public MyApp()
{
_systemTimer = new Timer("how ever you set your 1 second);
// Create your event handler for when it ticks over
_systemTimer.Elapsed += new ElapsedEventHandler(systemTimerElapsed);
}
protected void systemTimerElapsed(object sender, ElapsedEventArgs e)
{
_systemTimer.Stop();
//Do what you need to do
_systemTimer.Start();
//This way if it takes longer than a second it won't matter, another time won't kick off until the previous job is done
}
I will make it very easy for you;use Thread.Sleep() in another background thread and it is done!
If you know when are you finish than just use AutoResetEvent to keep threads in sync.
If you do not have any control on the update no callback , time is unknown I suggest to increase your timer interval!
var thread = new Thread((ThreadStart)delegate
{
While(true)
{
TSM.ModelObjectEnumerator myEnum = null;
myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
while (myEnum.MoveNext())
{
if (myEnum.Current != null)
{....}
}
Thread.Sleep(1000);
}
}
thread.Start();
Get each char from string from txtString and write on label one by one char with timerControl
int g = 0;
private void timerString_Tick(object sender, EventArgs e)
{
string a = txtString.Text;
int em = txtString.TextLength;
if (g < em)
{
lblString.Text = lblString.Text + a[g];
g++;
}
else timerString.Stop();
}
Call from
private void btnStringStart_Click(object sender, EventArgs e)
{
timerString.Start();
lblString.Text = "";
}
I would like to slow down a loop so that it loops every 5 seconds.
In ActionScript, I would use a timer and a timer complete event to do this. How would I go about it in C#?
You can add this call inside your loop:
System.Threading.Thread.Sleep(5000); // 5,000 ms
or preferable for better readability:
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
However, if your application has a user interface you should never sleep on the foreground thread (the thread that processes the applications message loop).
You can try using Timer,
using System;
public class PortChat
{
public static System.Timers.Timer _timer;
public static void Main()
{
_timer = new System.Timers.Timer();
_timer.Interval = 5000;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
Console.ReadKey();
}
static void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do Your loop
}
}
Also if your operation in loop can last more then 5 sec, You can set
_timer.AutoReset = false;
to disable next timer tick until operation finish in loop
But then end end of loop You need again to enable timer like
_timer.Enabled = true;
Don't use a loop at all. Set up a Timer object and react to its fired event. Watch out, because these events will fire on a different thread (the timer's thread from the threadpool).
Let's say you have a for-loop that you want to use for writing to a database every second. I would then create a timer that is set to a 1000 ms interval and then use the timer the same way you would use a while-loop if you want it to act like a for-loop. By creating the integer before the loop and adding to it inside it.
public patial class Form1 : From
{
timer1.Start();
int i = 0;
int howeverLongYouWantTheLoopToLast = 10;
private void timer1_Tick(object sender, EventArgs e)
{
if (i < howeverLongYouWantTheLoopToLast)
{
writeQueryMethodThatIAssumeYouHave(APathMaybe, i); // <-- Just an example, write whatever you want to loop to do here.
i++;
}
else
{
timer1.Stop();
//Maybe add a little message here telling the user the write is done.
}
}
}