Stopping DispatcherTimer in its own anonymous Tick event handler - c#

Is it safe to do something like this:
private void MyFunction()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
timer.Tick += (object sender, object e) =>
{
timer.Stop();
// Some code here
};
timer.Start();
}

Matt raise the point that the way you attach the anonymous method that there is no easy way to detach it. Here is a general pattern you can use to enable you to detach if necessary.
private void MyFunction()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 1);
EventHandler eh = null;
eh = (object sender, object e) =>
{
timer.Tick -= eh;
timer.Stop();
// Some code here
};
timer.Tick += eh;
timer.Start();
}
However in this specific case there is nothing wrong with the way your original code works since the timer becomes collectable as soon as it is stopped.

Yes. Your timer will fire once.

Edit: I'll rephrase my answer based on the comments. In the situation you've given, yes it's perfectly safe to use an anonymous delegate.
There are some situations in which adding an anonymous delegate and not detaching it could prevent your class from being garbage collected (for example, attaching an anonymous delegate to a singleton). See this answer for information about when it is and isn't necessary to detach the event handler.

Related

How to delay Silverlight's loading screen?

I have an experimental project in silverlight, that has no database and scarce resources. Now, I wanted to know if you can prolong or delay the Silverlight loading screen, so I can check what I have modified in the loading page. Problem is, it loads too fast for me to check. I have no data to fetch from the webservice or any resources needed. I'm just experimenting in modifying Silverlight's load page. Can this be done code-wise? Any help would be appreciated. Thanks.
Already found the answer. I just needed a timer for things. thanks for all the queries, anyway
private void Application_Startup(object sender, StartupEventArgs e)
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(10);
EventHandler eh = null;
eh = (s, args) =>
{
timer.Stop();
this.RootVisual = new Test();
timer.Tick -= eh;
};
timer.Tick += eh;
timer.Start();
}

Is there a QTimer::singleShot equivalent in C# Windows Forms?

Is there an analog to the following static function from the Qt library in Windows Forms?
http://doc.qt.io/qt-5/qtimer.html#singleShot
The best I can come up with is the following:
ThreadPool.QueueUserWorkItem((o) =>
{
Thread.Sleep(someNumberOfMilliseconds);
DoDelayedWorkHere();
});
UPDATE
This does the trick using System.Windows.Forms.Timer.
var timer = new System.Windows.Forms.Timer();
timer.Interval = someNumberOfMilliseconds;
timer.Tick += (o, args) =>
{
timer.Stop();
DoDelayedWorkHere();
};
timer.Start();
QTimer is a synchronous timer, just like the Winforms Timer. Threading or one of the other Timer classes is not a substitute. A single-shot is easy to implement, just set the timer's Enabled property to false in the Tick event handler. No danger of a race:
private void timer1_Tick(object sender, EventArgs e) {
((Timer)sender).Enabled = false;
// etc..
}
How about System.Threading.Timer? Use one of the constructors with the period parameter and specify the parameter accordingly.

How do I make sure no handlers are attached to an event?

I am adding an event handler like this:
theImage.MouseMove += new MouseEventHandler(theImage_MouseMove);
but in my application, this code gets run every time the page is shown, so I want to attach the event handler only once, but how can I tell if a handler has been set yet or not, something like this:
if(theImage.MouseMove == null) //error
theImage.MouseMove += new MouseEventHandler(theImage_MouseMove);
I might me missing something, but if you just want to make sure that the handle is only called once, why don't you use -= before adding it. Something like this:
public static void Main(string[] args)
{
var timer = new Timer(1000);
timer.Elapsed -= new ElapsedEventHandler(timer_Elapsed);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Elapsed -= new ElapsedEventHandler(timer_Elapsed);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
System.Threading.Thread.Sleep(4000);
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hit!");
}
The handler will only run once every second.
You can shorten it down if you only want to attach once:
theImage.MouseMove -= theImage_MouseMove; //If it wasn't attached, doesn't matter
theImage.MouseMove += theImage_MouseMove;
I'm not sure if this is the best solution, but the way I usually do this is to simply use an unsubscribe before the subscribe.
If you do something like:
TheImage.MouseMove -= new MouseEventHandler(theImage_MouseMove);
TheImage.MouseMove += new MouseEventHandler(theImage_MouseMove);
It will only ever get added once. If it doesn't already exist (the first time it's triggered), the -= doesn't hurt anything if it hasn't been subscribed to previously.
theImage.MouseMove.GetInvocationList().Length

Timer, event and garbage collection : am I missing something?

Consider the following code :
class TestTimerGC : Form
{
public TestTimerGC()
{
Button btnGC = new Button();
btnGC.Text = "GC";
btnGC.Click += (sender, e) => GC.Collect();
this.Controls.Add(btnGC);
System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
tmr.Interval = 1000;
tmr.Tick += (sender, e) => this.Text = DateTime.Now.ToString();
tmr.Start();
}
}
If I'm not mistaken, after the tmr variable goes out of scope, the Timer isn't referenced anywhere, so it should be eligible for garbage collection. But when I click the GC button, the timer continues to run, so I guess it wasn't collected...
Does anyone have an explanation for that ?
PS: it's not a real program of course, I was just trying to prove a point to someone... but my proof didn't work ;)
OK, I think I know what's going on... I looked at the code of the Timer class with Reflector, and I found the following instruction in the setter of the Enabled property :
this.timerRoot = GCHandle.Alloc(this);
So, when it is started, the timer allocates a GCHandle for itself, which prevents its collection by the GC...

How to block a timer while processing the elapsed event?

I have a timer that needs to not process its elapsed event handler at the same time. But processing one Elapsed event may interfere with others. I implemented the below solution, but something feels wrong; it seems like either I should be using the timer differently or using another object within the threading space. The timer seemed to fit best because I do need to periodically check for a status, but sometimes checking will take longer than my interval. Is this the best way to approach this?
// member variable
private static readonly object timerLock = new object();
private bool found = false;
// elsewhere
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed = Timer_OnElapsed;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
lock(timerLock)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
}
}
You could set AutoReset to false, then explicitly reset the timer after you are done handling it. Of course, how you handle it really depends on how you expect the timer to operate. Doing it this way would allow your timer to drift away from the actual specified interval (as would stopping and restarting). Your mechanism would allow each interval to fire and be handled but it may result in a backlog of unhandled events that are handled now where near the expiration of the timer that cause the handler to be invoked.
timer.Interval = TimeSpan.FromSeconds(5).TotalMilliseconds;
timer.Elapsed += Timer_OnElapsed;
timer.AutoReset = false;
timer.Start();
public void Timer_OnElapsed(object sender, ElapsedEventArgs e)
{
if (!found)
{
found = LookForItWhichMightTakeALongTime();
}
timer.Start();
}
I usually stop the timer while processing it, enter a try/finally block, and resume the timer when done.
If LookForItWhichMightTakeALongTime() is going to take a long time, I would suggest not using a System.Windows.Forms.Timer because doing so will lock up your UI thread and the user may kill your application thinking that it has frozen.
What you could use is a BackgroundWorker (along with a Timer if so desired).
public class MyForm : Form
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MyForm()
{
InitializeComponents();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
backgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = LookForItWhichMightTakeALongTime();
}
private void backgroundWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
found = e.Result as MyClass;
}
}
And you can call RunWorkerAsync() from anywhere you want to, even from a Timer if you want. And just make sure to check if the BackgroundWorker is running already since calling RunWorkerAsync() when it's running will throw an exception.
private void timer_Tick(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
timer.enabled = false
or
timer.stop();
and
timer.enabled = true
or
timer.start();
I use the System.Threading.Timer like so
class Class1
{
static Timer timer = new Timer(DoSomething,null,TimeSpan.FromMinutes(1),TimeSpan.FromMinutes(1));
private static void DoSomething(object state)
{
timer = null; // stop timer
// do some long stuff here
timer = new Timer(DoSomething, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
}
}

Categories

Resources