How can I automatically dispose of, and nullify, a timer after it's elapsed?
The sender is a random object with no method; I can't dynamically access the original timer via the EventHandler.
Another function will want to check if this timer is null, or running (and interrupt it).
I could run logic such as:
if (timer != null && timer.Enabled) but I'd rather if (timer != null)
I could also instantiate the variable with a dummy timer, and simply check if this is enabled, but I know if this variable were to suddenly become null, the program would crash.
Should I just use the prior if statement; won't these timers in memory start to add up?
EDIT:
static void Main()
{
Timer timer = null;
timer = new Timer(5000);
timer.Elapsed += (sender, e) => {
var T = (Timer)sender;
T.Dispose();
T = null;
Console.WriteLine(T);
};
timer.Start();
while (true)
{
Console.WriteLine(timer);
System.Threading.Thread.Sleep(1000);
}
}
The sender is a random object with no method
It's not. The object is your timer. You just need to cast it back to its original type:
private void TimerTick(object sender, EventArgs e)
{
var timer = (Timer)sender;
timer.Enabled = false;
}
Related
In top of form1
label5.Text = "00:00:00";
In the dowork event
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DirectoryInfo diri = new DirectoryInfo(#"d:\c-sharp");
WalkDirectoryTree(diri);
}
WalkDirectoryTree method
int tfiles = 0;
int tdirs = 0;
void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
System.IO.FileInfo[] files = null;
System.IO.DirectoryInfo[] subDirs = null;
string[] workerResult = new string[4];
try
{
files = root.GetFiles("*.cs");
tdirs ++;
workerResult[1] = root.FullName;
workerResult[3] = tdirs.ToString();
backgroundWorker1.ReportProgress(0,workerResult);
}
catch (UnauthorizedAccessException e)
{
}
catch (System.IO.DirectoryNotFoundException e)
{
}
if (files != null)
{
foreach (System.IO.FileInfo fi in files)
{
tfiles += files.Length;
if (files.Length > 0)
{
try
{
int Vara = File.ReadAllText(fi.FullName).Contains("Form1") ? 1 : 0;
if (Vara == 1)
{
workerResult[2] = files[0].FullName;
}
}
catch (FileNotFoundException e)
{
}
}
workerResult[0] = tfiles.ToString();
backgroundWorker1.ReportProgress(0, workerResult);
Thread.Sleep(10);
}
subDirs = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirs)
{
WalkDirectoryTree(dirInfo);
}
}
}
In the constructor i start the backgroundworker
InitializeComponent();
label1.Visible = false;
label2.Visible = false;
label3.Visible = false;
label4.Visible = false;
label5.Text = "00:00:00";
pbt.Size = new Size(984, 23);
pbt.Location = new Point(12, 358);
this.Controls.Add(pbt);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.RunWorkerAsync();
I want to make that once the backgroundworker start the whole process start in the dowork event report to label5 the time elapsed.
First how can i do it ? and should i use a timer or stopwatch ?
Since you are wanting to measure the elapsed time taken by a process, by definition you should be using the System.Diagnostics.Stopwatch class. MSDN defines it as:
Stopwatch Class
Provides a set of methods and properties that you can use to accurately measure elapsed time.
However, you will also need a System.Windows.Forms.Timer control on your form in order to update the field while the work is in progress. The timer's Interval property controls how often you want to update the field, but don't rely on this to determine the actual value to display. Instead, use the Elapsed property of the stopwatch.
Drop a Timer onto your form.
Create an instance of the stopwatch class in your C# code:
private readonly Stopwatch _stopwatch = new Stopwatch();
Just before you call RunWorkerAsync(), call timer1.Start()
Inside the background worker's DoWork event:
_stopwatch.Restart();
// do your work
_stopwatch.Stop();
In the timer's Tick event, update your label with the value of the stopwatch's Elapsed property. Format it however you like.
lblElapsed.Text = _stopwatch.Elapsed.ToString(#"hh\:mm\:ss\.f");
In the RunWorkerCompleted event, call timer1.Stop()
I've posted a complete working example here.
I would capture the current time on a variable or field and start a timer before the invocation of RunWorkerAsync. On each tick of the timer update the label with the elapsed time (current time minus captured starting time). Stop the timer when the worker ends using RunWorkerCompleted event.
If you're talking about displaying only the total time it took for the BackgroundWorker to do its job (i.e. not incremental updates):
Grab a timestamp (e.g. DateTime.UtcNow, if you don't need sub-millisecond precision) just prior to invoking RunWorkerAsync. Pass this value into the RunWorkerAsync method (using the overload that accepts an object parameter). Catch the RunWorkerCompleted event in your form, and retrieve the timestamp from the UserState property of those event args. Set your label to the delta of the current time minus the UserState's timestamp.
For example:
backgroundWorker1.RunWorkerAsync(DateTime.UtcNow);
// elsewhere in your form:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_myLabel.Text = DateTime.UtcNow - (DateTime)e.UserState;
}
I want to wait to a timer finish and then return from a function. I tried this:
while(timer1.Enabled)
{
Application.DoEvents();
}
return value;
But it didn't work and the function returned before the timer really finished. Here's the full function:
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
int[] foo()
{
do_something1();
int[] some_value;
timer1.Interval = 1000;
timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
{
if (browser.ReadyState == WebBrowserReadyState.Complete)
{
timer1.Stop();
baa(some_value);
}
});
timer1.Start();
while (timer1.Enabled)
{
Application.DoEvents();
}
return some_value;
}
I think what you actually want is to wait until the browser is ready. If so you can use a loop like this, and instead of Application.DoEvents() I recommend using async/await feature:
while(browser.ReadyState != WebBrowserReadyState.Complete)
{
// you need to make your method async in order to use await
await Task.Delay(1000);
}
// do your job
Or better you can handle DocumentCompleted event of WebBrowser.
You can use a Thread instead of a Timer. Launch your waiting method in a Thread and simply wait it to finish with thread.IsAlive.
Your code must look like this:
int[] some_value;
int intervalle = 1000;
Thread thread = new Thread(new ThreadStart(delegate()
{
while (true)
{
Thread.Sleep(intervalle);
if (browser.ReadyState == WebBrowserReadyState.Complete)
{
baa(some_value);
return;
}
}
}));
thread.Start();
while (thread.IsAlive)
{
Application.DoEvents();
}
return some_value;
Instead of using Await/Async and change the method signature you could use CountdownEvent and threading.
using System.Theading;
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
int[] foo()
{
int numberOfIterations = interval time * number of intervals; // initialize this to the proper number of times to decrement the counter. If we are decrementing every 1000 ms
CountdownEvent countDown = new CountdownEvemt(numberOfIterations);
do_something1();
int[] some_value;
timer1.Interval = 1000;
timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
{
if (browser.ReadyState == WebBrowserReadyState.Complete)
{
timer1.Stop();
baa(some_value);
// since this seems where you want to shut down the method we need to trigger the countdown
int countLeft = countDown.CurrentCount;
countDown.Signal(countLeft);
} else {
if(countDown.CurrentCount - 1 == 0) {
countDown.Reset(); // we don't want to finish yet since we haven't reached the proper end condition so reset the counter
}
countDown.Signal(); // will decrement the counter
}
});
timer1.Start();
countDown.Wait(); // will wait 'til the counter is at 0 before continuing
return some_value;
}
The CountdownEvent will block the current thread until the counter reaches 0. Since the Timer class uses a ThreadPool for its callback, that event will still fire and work as normal.
I will not go into how good or bad this approach is. But you can simply do this with a flag.
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
int[] foo()
{
do_something1();
int[] some_value;
bool doneWaiting = false;
timer1.Interval = 1000;
timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
{
if (browser.ReadyState == WebBrowserReadyState.Complete)
{
timer1.Stop();
baa(some_value);
doneWaiting = true;
}
});
timer1.Start();
while (!doneWaiting)
{
Application.DoEvents();
}
return some_value;
}
And you should probably put a Thread.Sleep in the while loop also.
Simply put some_value into a class-level variable, then have the timer raise an event. Any function calling your function can (before the call) subscribe to the event and then handle it.
I have a program that is continuously running.
When I start the program, I have a BackgroundWorker (InitialStart.cs):
BackgroundWorker recordingSyncWorker = new BackgroundWorker();
recordingSyncWorker.DoWork += new DoWorkEventHandler(RecordingSyncCheck);
recordingSyncWorker.WorkerSupportsCancellation = false;
recordingSyncWorker.WorkerReportsProgress = false;
recordingSyncWorker.RunWorkerAsync();
void RecordingSyncCheck(object sender, DoWorkEventArgs e)
{
cHandler ch = new cHandler();
Timer theTimer;
int seconds = 1;
if (taskSeconds != null && taskSeconds != "")
seconds = Convert.ToInt32(taskSeconds);
int milliseconds = seconds * 1000;
theTimer = new Timer(10000);
theTimer.Elapsed += new ElapsedEventHandler(ch.SyncMethod);
theTimer.Interval = milliseconds;
theTimer.Enabled = true;
}
And I have two methods in another class (cHandler.cs):
SyncMethod(object source, System.Timers.ElapsedEventArgs e)
{
// random code
}
private string SDCardCheck(object whatever)
{
//more code
}
SDCardCheck gets called thru WCF, so it's like there is another instance of cHandler.cs running. Is there a way for me to pause the BackgroundWorker when I call SDCardCheck?
Don't use a BackgroundWorker just to start a timer. Starting a timer is not a long running operation; it can be done directly from the UI thread.
Your other method can disable the timer to stop it from firing, and then enable it again to allow it to continue firing, in order to effectively pause its execution.
this time I come to you guys asking for help with Timers (System.Timers to be specific, I believe)
I need to make a timer that runs a function every second, so far this is what I've got:
public class Game1 : Microsoft.Xna.Framework.Game
{
Timer CooldownTracker;
protected override void LoadContent()
{
CooldownTracker = new Timer();
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
}
private void DecreaseCooldown(List<Brick> bricks)
{
foreach (Brick brick in bricks)
{
if (brick.Cooldown == 0)
brick.Cooldown = 2;
else
brick.Cooldown--;
}
}
}
...How do I make the timer run the DecreasedCooldown(List bricks) function? I've tried with Timer.Elapsed but I get nothing, I can't pass down the arguments that way. Any ideas?
Thanks!
You need to attach a Timer Elapsed event like:
CooldownTracker = new Timer();
CooldownTracker.Elapsed += CooldownTracker_Elapsed; //HERE
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
and then the event:
void CooldownTracker_Elapsed(object sender, ElapsedEventArgs e)
{
DecreaseCooldown(yourList);
}
You can use Thread if you want. It's not so accurate maybe cause of ThreadPool but can help.
Like
private bool run = true;
Thread timer = new Thread(Run);
timer.Start();
And define Run
private void Run()
{
while(run)
{
// Call function
Thread.Sleep(1000); //Time in millis
}
}
if you get cross-thread exception try to use for loop instead of foreach or lock your resources.
In this code after starting timer again it starts from the current value instead of the vale it stopped. How to pause this timer?
public Page1()
{
InitializeComponent();
_rnd = new Random();
_timer = new DispatcherTimer();
_timer.Tick += new EventHandler(TimerTick);
_timer.Interval = new TimeSpan(0, 0, 0, 1);
}
void TimerTick(object sender, EventArgs e)
{
var time = DateTime.Now - _startTime;
txtTime.Text = string.Format(Const.TimeFormat, time.Hours, time.Minutes, time.Seconds);
}
public void NewGame()
{
_moves = 0;
txtMoves.Text = "0";
txtTime.Text = Const.DefaultTimeValue;
Scrambles();
while (!CheckIfSolvable())
{
Scrambles();
}
_startTime = DateTime.Now;
_timer.Start();
//GridScrambling.Visibility = System.Windows.Visibility.Collapsed;
}
private void Pause_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
NavigationService.Navigate(new Uri("/Page4.xaml", UriKind.Relative));
_timer.Stop();
}
private void Play_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
_timer.Start();
}
As this says that the Stop method only changes the IsEnabled property and this says that this property only prevents the Tick event to be raised, I don't think that there is a method to simply 'pause' the timer. The best way is to reinitialize the timer each time you have "paused" it, if you really want it to start clean again.
But I do not think that this is you real problem. When you pause your game the timer stops working. When you continue it the timer starts working again. When you now try the calculate the time from THIS moment till the start time, then you make a big mistake: you have to ignore the paused time. Because when you play the game 2s, then pause it for 10s and then continue the game, the timer shows 12s, instead of 2s, doesn't it? Maybe you should store the paused times in a variable and substract that from the real game time.