I am making a program which has to check a data base once on every 30 or 60 minutes and display the results, if there are any, in the windows form interface. Of course, the other functions which the from provides access to, should still be usable while the data base check is being executed. To this end, I am using System.Timers.Timer which executes a method on a different thread from the UI one (If there is something wrong with using this approach, please feel free to comment on it). I wrote a small and simple program in order to test hot things work, only to notice that I cant really set the Interval to over ~ 1 minute ( I need 30 minutes to an hour). I came up with this solution:
public partial class Form1 : Form
{
int s = 2;
int counter = 1; //minutes counter
System.Timers.Timer t;
public Form1()
{
InitializeComponent();
t = new System.Timers.Timer();
t.Elapsed += timerElapsed;
t.Interval = 60000;
t.Start();
listBox1.Items.Add(DateTime.Now.ToString());
}
//doing stuff on a worker thread
public void timerElapsed(object sender, EventArgs e)
{
//check of 30 minutes have passed
if (counter < 30)
{
//increment counter and leave method
counter++;
return;
}
else
{
//do the stuff
s++;
string result = s + " " + DateTime.Now.ToString() + Thread.CurrentThread.ManagedThreadId.ToString();
//pass the result to the form`s listbox
Action action = () => listBox2.Items.Add(result);
this.Invoke(action);
//reset minutes counter
counter = 0;
}
}
//do other stuff to check if threadid`s are different
//and if the threads work simultaneously
private void button1_Click(object sender, EventArgs e)
{
for (int v = 0; v <= 100; v++)
{
string name = v + " " + Thread.CurrentThread.ManagedThreadId.ToString() +
" " + DateTime.Now.ToString(); ;
listBox1.Items.Add(name);
Thread.Sleep(1000); //so the whole operation should take around 100 seconds
}
}
}
But this way, the Elapsed event is being raised and the timerElapsed method called once every minute, it seems kinda useless. Is there a way to actually set longer timer interval ?
Interval is in miliseconds,so it seems that you've set your interval for 60 seconds:
t.Interval = 60000; // 60 * 1000 (1 minute)
If you want to have 1 hour interval then you need to change your interval to:
t.Interval = 3600000; // 60 * 60 * 1000 (1 hour)
Related
comboBox selectedindexchanged event:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
updateTime = Convert.ToInt32(comboBox1.SelectedItem);
xpProgressBar1.Position = 0;
counter = 0;
panel1.Select();
}
Update method:
public void Update()
{
counter += 1;
int position = (int)Math.Round((counter / updateTime) * 100);
xpProgressBar1.Text = counter.ToString() + " %";
xpProgressBar1.Position = position;
if (counter == 10)
{
if (!backgroundWorker1.IsBusy)
{
timer1.Stop();
backgroundWorker1.RunWorkerAsync();
}
counter = 0;
}
}
Timer tick event:
private void timer1_Tick(object sender, EventArgs e)
{
Update();
}
In the combBox by default it's on the first item the number 10 then i can change and select the item with the number 30,50,60,120,300 and all this values are in seconds.
The timer1 interval is set to 1000
The problem is when it's on 10 by default when running the program or if i change it back to 10 in the comboBox it's working good. What it does it's counting 10 seconds and updating the progressBar(xpProgressBar1) by 10's i mean each second the progressBar move by 10 percentages. So after 10 seconds it's getting to 100 percentages.
But when i change the comboBox to the second item to 30 it should count now 30 seconds untill 100%
So i'm not sure in what steps it should move and how to do it. Same if i change it to 120 then it should move progress 120 seconds and again i'm not sure what steps and how to do it so it will get to 100%
What it does now for example if i change it to 120 i see it start counting to 120 by steps of 1 but then when it's getting to 10% it's jumping back to the start and not continue.
It should keep counting the whole 120 seconds untill 100%
If i change it to 30 i see it also counting by steps of 1 each time but again in 10% it's jumping to the start and not continue.
When it's on 10 it's counting by steps of 10 untill 100% so i wonder what should i do and how in the others if it's on 120 to step by 120 ? not logic. So tmake them all to step by 1 also the when it's on 10 ? And again how to do it so it will not stop a 10% and start over again.
Now i changed in the Update method the line if (counter == 10) to:
if (counter == updateTime)
So now if i change in the comboBox select 120 it will count in steps of 1 untill 120 but now when it will get the progressBar to 100% it will keep counting untill 120.
There is no sync between the 120 seconds and the 100% of the progressBar.
EDIT
The Update method:
private int _updateCounter;
public void Update()
{
counter += 1;
xpProgressBar1.Text = counter.ToString() + " %";
xpProgressBar1.Position = _updateCounter++ * 10;
if (counter == 10)
{
if (!backgroundWorker1.IsBusy)
{
timer1.Stop();
backgroundWorker1.RunWorkerAsync();
}
counter = 0;
}
}
This is called prescaler (frequency divider). You have single clock source (Timer) with fastest frequency using which you can achieve needed frequencies by skipping certain calls (events).
All you miss is that skipping:
private int _timer1Ticks;
private void timer1_Tick(object sender, EventArgs e)
{
if(_timer1Ticks++ >= int.Parse(comboBox1.Text) / 10)
{
_timer1Ticks = 0;
Update();
}
}
This way Update will be called exactly 10 times, disregard of combobox selection.
And to calculate progress:
private int _updateCounter;
public void Update()
{
xpProgressBar1.Position = _updateCounter++ * 10;
...
// do not forget to stop timer
if(_updateCounter == 10)
{
timer1.Stop();
_updateCounter = 0; // add some cleanup if using timer more than once
_timer1Ticks = 0;
...
}
}
I am using a timer to run a method every 16 minutes. I also want to run a second method every minute for 15 minutes in-between.
Below is the code I am using:
int count = 0;
private void cmdGo_Click(object sender, EventArgs e)
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 960000; // specify interval time - 16 mins
t.Tick += new EventHandler(timer_Tick);
t.Start();
}
void timer_Tick(object sender, EventArgs e)
{
RunMethod1();
while(count < 15)
{
//waiting for 60 seconds
DateTime wait = DateTime.Now;
do
{
Application.DoEvents();
} while (wait.AddSeconds(60) > DateTime.Now);
RunMethod2();
}
}
The above code seems to work fine but the ‘do while’ loop to wait for 60 seconds is very CPU heavy.
I tried to use Thread.Sleep(60000) but this freezes up the Interface and also tried to add a second timer within timer_Tick but this doesn’t seem possible. Can a second timer be added within the EventHandler of the first?
Is there any other method to achieve this without being so CPU intensive?
Thanks!
Warren
NOTE: Sorry guys, there was a typo in my original post. The 60 second wait do, while loop should have been within the while < 15 loop. Just updated the code snippet.
So:
RunMethod1() should be executed every 16 mins
RunMethod2() should be executed every 1 min (15 times) in between the 16 min tick
It would make more sense to have a counter to store how many times the clock has gone off. Then set your timer interval to fire once a minute so not doing anything in between...
That way you could just do...
private int Counter;
private void cmdGo_Click(object sender, EventArgs e)
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 60000; // specify interval time - 1 minute
t.Tick += new EventHandler(timer_Tick);
t.Start();
}
// Every 1 min this timer fires...
void timer_Tick(object sender, EventArgs e)
{
// If it has been 16 minutes then run RunMethod1
if (++Counter >= 16)
{
Counter = 0;
RunMethod1();
return;
}
// Not yet been 16 minutes so just run RunMethod2
RunMethod2();
}
You could await a task Delay so the UI will keep responding
async void timer_Tick(object sender, EventArgs e)
{
RunMethod1();
while (count < 15)
{
//waiting for 60 seconds
await Task.Delay(60000);
RunMethod2();
}
}
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.
I am using Multimedia timer with a resolution of 1 ms and a period of 10 ms. The problem is that the multimedia timer badly interrupts for the first two events as I get a difference of 1 ms , which is not what I want.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.mmtimer.Tick += new System.EventHandler(this.mmtimer_Tick);
}
Multimedia.Timer mmtimer = new Multimedia.Timer();
private void Form1_Load(object sender, EventArgs e)
{
mmtimer.Resolution = 1;
mmtimer.Mode = Multimedia.TimerMode.Periodic;
mmtimer.Period = 10;
mmtimer.SynchronizingObject = this;
}
private void S_Click(object sender, EventArgs e)
{
TD.Items.Clear();
MT.Items.Clear();
delta_MT.Items.Clear();
double T = DateTime.Now.Hour * 60 * 60 * 1000 + DateTime.Now.Minute * 60 * 1000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;
Point C = Cursor.Position;
TD.Items.Add(C.ToString());
MT.Items.Add(T.ToString());
try
{
mmtimer.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
}
private void Stop_Click(object sender, EventArgs e)
{
mmtimer.Stop();
double T = DateTime.Now.Hour * 60 * 60 * 1000 + DateTime.Now.Minute * 60 * 1000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;
Point C = Cursor.Position;
TD.Items.Add(C.ToString());
MT.Items.Add(T.ToString());
M();
}
private void mmtimer_Tick(object sender, System.EventArgs e)
{
double T = DateTime.Now.Hour * 60 * 60 * 1000 + DateTime.Now.Minute * 60 * 1000 + DateTime.Now.Second * 1000 + DateTime.Now.Millisecond;
Point C = Cursor.Position;
TD.Items.Add(C.ToString());
MT.Items.Add(T.ToString());
}
void M()
{
for (int i = 0; i < MT.Items.Count - 1; i++)
{
double A1 = Convert.ToDouble(MT.Items[i + 1]);
double A2 = Convert.ToDouble(MT.Items[i]);
double d = A1 - A2;
delta_MT.Items.Add(d);
}
}
}
Could you please tell how to fix the first two interrupts? if it is possible.
When the multimedia timer is running at standard resolution before you change the resolution to 1, the timer will first complete its current period. The new period will only be effective after the next interrupt. Setting the multimedia timing is a synchronous job. Thus it may be delayed by as much as 20ms (interrupt period on some systems).
If you want to make sure that you timing scheme works from the start of your main code you should make the calls to the multimedia time configuration 2 interrupt periods ahead of the main code. I'd with 50 ms you should be OK.
The delay you observe for the first interrupts depends on when your call was made with respect to the systems interrupt.
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);
}