I am trying to use DispatcherTimer for multiple elements (visual, moving stackpanel)
It is possible to call the same DispatcherTimer_Tick for multiple elements? and all of them to move at the same time, but using a loop? And also how should I delay the dispatcher timer to create a new troop after a period of time?
for the moment I've dont something like this
for (int i = 1; i < 3; i++)
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 1);
index = i;
FirstTroop(i);
dispatcherTimer.Start();
}
It is possible to call the same DispatcherTimer_Tick for multiple elements?
Yes you can call dispatcherTimer_Tick(null, null) anywhere in your code. But it is recommended to leave the event handler for only handling tick events and instead call a more meaningful method for this purpose. like a SpawnTroop:
dispatcherTimer_Tick(object sender, EventArgs e)
{
SpawnFirstTroop();
}
and all of them to move at the same time, but using a loop?
So you need to call dispatcherTimer_Tick inside a loop.
void Start()
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(1000);
dispatcherTimer.Start();
}
dispatcherTimer_Tick(object sender, EventArgs e)
{
for (int i = 1; i < 3; i++)
{
SpawnTroop(i);
}
}
And also how should I delay the dispatcher timer to create a new troop after a period of time?
According to MSDN:
If a System.Timers.Timer is used in a WPF application, it is worth noting that the System.Timers.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. Reasons for using a DispatcherTimer opposed to a System.Timers.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.
There are multiple solutions for this:
You can't use a Thread.Sleep with dispatcherTimer_Tick. But you can use Thread.Sleep with a Timer to delay inside timer's tick event handler.
You can write more code for your dispatcherTimer to enable two intervals (like a simple integer counter withing the event handler). this approach is not recommended.
You can use two dispatcher timers, one for queuing/requesting new objects, one for creating/showing them.
Related
In my application I'm using two Timer, each Timer use a BackgroundWorker. Here the declaration:
DispatcherTimer timer1 = new DispatcherTimer();
DispatcherTimer timer2 = new DispatcherTimer();
BackgroundWorker worker1 = new BackgroundWorker();
BackgroundWorker worker2= new BackgroundWorker();
I using timer1 for perform an heavy method with a BackgroundWorker and timer2 for execute another BackgroundWorker that check the content of a file.
In this way I assign the event to BackgroundWorkers:
worker1.DoWork += worker_DoWork;
worker1.RunWorkerCompleted += worker_RunWorkerCompleted;
worker1.WorkerSupportsCancellation = true;
worker2.DoWork += worker_DoWork2;
worker2.RunWorkerCompleted += worker_RunWorkerCompleted2;
worker2.WorkerSupportsCancellation = true;
Now timer1 have a range of 15 minutes so the BackgroundWorker execute the heavy method each 15 minutes. And timer2 have a range of 1 second. With the timer1 all working good, but the problems are coming when I've added the timer2.
As I said before this timer allow me to start a method that read a file through the worker2, this file have a property, if this property change I need to perform some special activity. Until here no problem.
What I did is the following:
//This method is called by MainWindow
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
This is the Tick event associated to timer2
private void Event_Tick(object sender, EventArgs e)
{
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
else
{
Console.WriteLine("worker1 is busy!");
}
}
I don't need to add here the DoWork, is just a parsing of a file, very useless for the question. When worker2 complete the task I did this:
private void worker_RunWorkerCompleted2(object sender, RunWorkerCompletedEventArgs e)
{
timer1.Start();
ReadFile();
}
How you can see I start the timer1 again, and execute again the ReadFile method. Now if timer1 has reached the interval, so 15 minutes has passed, should execute the timer1.Tick += new EventHandler(Heavy_Tick); that execute the DoWork to worker1. But the timer1 never start.
I can't figure out to this, what am I doing wrong?
Now I get it!
You want to execute worker1 every 15 minutes and worker2 every second but only when worker1 is not busy. Your problem is this here:
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
and this:
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
Set both timer intervals and tick event handlers during startup, e.g. Form_Load()or at the beginning of Main(). Start them there too. You should not have to stop any timer at all!
By setting the interval, all you have to do is handle the Tick() event. Remove your .Start() and Stop() calls from your WorkerCompletedand Tick methods and you should do fine.
So a lot could be going on here but you should make sure that:
You timer isn't storing it's old progress and you are checking for a certain length of time before stopping. This will automatically cause the timer to stop when restarting.
The timer.stop() function is not disposing your object to an un-restart-able state.
You aren't accessing the timer variable through some pointer that is maintain a stopped value. (Unlikely but annoying when it happens)
I'd personally consider just pausing the timer and resetting the progress, instead of fully stopping it since this is causing issues.
I have this code:
private void Form1_Load(object sender, EventArgs e)
{
/*start update timer*/
System.Timers.Timer updateticker = new System.Timers.Timer();
updateticker.Elapsed += new ElapsedEventHandler(update_overload);
//10 minute ticker
updateticker.Interval = 600000;
//30 sec ticker
updateticker.Interval = 30000;
updateticker.Enabled = true;
System.Timers.Timer guiTimer = new System.Timers.Timer();
guiTimer.Elapsed += new ElapsedEventHandler(idle_display);
//1 minute ticker
guiTimer.Interval = 60000;
//30 sec ticker
//updateticker.Interval = 30000;
guiTimer.Enabled = true;
}
//run front end idle timer
public void idle_display(object source, ElapsedEventArgs e)
{
if (minutes_left > 0) {
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = "Time until next automatic update: "+ minutes_left + " minutes.";
}
Visual studio is flagging the final line of the second function as unsafe cross threading. Can anyone suggest how I rewrite this to solve the issue?
Cheers
Use System.Windows.Forms.Timer instead of System.Timers.Timer
or use SynchronizingObject property of Timer.
When SynchronizingObject is null, the method that handles the Elapsed event is called on a thread from the system-thread pool. For more information on system-thread pools, see ThreadPool.
When the Elapsed event is handled by a visual Windows Forms component, such as a button, accessing the component through the system-thread pool might result in an exception or just might not work. Avoid this effect by setting SynchronizingObject to a Windows Forms component, which causes the method that handles the Elapsed event to be called on the same thread that the component was created on.
As others suggested, use System.Windows.Forms.Timer. Unlike System.Threading.Timer, which operates on Thread Pool threads, it guarantees you that the tick event is invoked on the UI thread.
The UI thread is the only thread allows to modify the UI. This is why you get an exception trying to write lbl_dyn_status.Text.
Use System.Windows.Forms.Timer timer instead of System.Timers.Timer.
Change the handler to
public void IdleDisplay(object source, ElapsedEventArgs e)
{
if (lbl_dyn_status.InvokeRequired)
{
this.Invoke(IdleDisplay)
}
else
{
if (minutes_left > 0)
{
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = string.Format(
"Time until next automatic update: {0} minutes.",
minutes_left);
}
}
This way allows you to use the thread free System.Threading.Timer but checks for a cross-thread call in the handler. If detected the call is invoked on the main GUI thread, via the Form class.
This is described on MSDN in more detail here.
More generally, you should not use timers to count time like this. The more thread bound your timer is, the more it is likely to diverge from real elapsed time. You can use your timer to schedule an update of your clock but, you should calculate elapsed time since some fixed point rather than using an iterative counter.
I'm trying to figure out a way in Silverlight / C# to make a DispatchTimer run only once.
I have a user form and when submitted I want to display a message for 10 seconds and then disappear and kill the DispatchTimer thread.
I know how to make a DispatchTimer that repeats:
clock.Interval = TimeSpan.FromSeconds(10);
clock.Tick += clockTick;
clock.Start();
But I want that thread to end as soon as it completes.
This should work for you:
DispatcherTimer clock = new DispatcherTimer();
clock.Interval = TimeSpan.FromSeconds(10);
clock.Tick += (object sender, EventArgs e) =>
{
clock.Stop();
// Some code here
};
clock.Start();
An anonymous event handler will also keep things "in the same place" in case you don't want to widen the scope of your DispatcherTimer object.
Stop the timer in your clockTick handler once it fires.
I am trying to update an ObservableCollection that is data bound to the UI. I know that to do this I need to use Dispatcher and BeginvInvoke(), and to make it so that the UI doesn't freeze up when I do so, using a BackgroundWorker is a good way to go about it. In any event, I have all this, compiled and running, but nothing happens. I need to update the UI every 2 minutes or so, so I am also using a DispatcherTimer
This works, because DispatcherTimer is part of Dispatcher, but freezes the UI:
DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();
private void dispTimer_Tick(object sender, EventArgs e)
{
PartialEmployees.Clear();
}
So, using the BackgroundWorker I pieced together this:
DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();
private void dispTimer_Tick(object sender, EventArgs e)
{
BackgroundWorker _worker = new BackgroundWorker();
_worker.DoWork += DoWork;
_worker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
Dispatcher.CurrentDispatcher.BeginInvoke( new Action(()=>
{
PartialEmployees.Clear();
}));
}
But nothing happens to the UI. What am I missing/not doing correctly?
You have two problems:
When you use Dispatcher.CurrentDispatcher from the background thread, it is getting the background thread's Dispatcher, not the UI thread's Dispatcher.
From your description I gather that your PartialEmployees.Clear() method takes significant time to execute and you want to avoid locking the UI thread during the execution. However, having a BackgroundWorker invoke PartialEmployees.Clear() on your UI thread will have the same effect as using the DispatcherTimer, so you need a different solution than the one you are going for.
If you only want to fix the Dispatcher.CurrentDispatcher problem, just store the current Dispatcher in a local variable like this:
private void dispTimer_Tick(object sender, EventArgs e)
{
var uiDispatcher = Dispatcher.CurrentDispatcher;
BackgroundWorker _worker = new BackgroundWorker();
_worker.DoWork += (sender, e) =>
uiDispatcher.BeginInvoke(new Action(() =>
{
PartialEmployees.Clear();
}));
_worker.RunWorkerAsync();
}
This will cause your UI change to work but it will still lock up the UI during the change, exactly as if you had not used BackgroundWorker. The reason for this is:
The DispatcherTimer fires, executing on the UI thread. All it does (dispTimer_Tick) is start a BackgroundWorker and then exit.
The BackgroundWorker executes on its own therad. All it does is schedule a Dispatcher callback and then exit.
The Dispatcher callback executes on the UI thread again. It calls PartialEmployees.Clear() which takes a while, locking up your UI thread while it executes.
So your behavior is the same as if the DispatcherTimer callback had called PartialEmployees.Clear() directly: In each case the time-consuming operation is executed on the UI thread.
The reason for the lockup is that any time you do a large piece of work on the UI thread you will get a momentary lockup while it runs. The solution is to break your work into smaller portions and do them one at a time, either from a DispatcherTimer or a BackgroundWorker. In your case, examine the code for PartialEmployees.Clear() to see if it can be done incrementally.
The problem here is that you're using the method Dispatcher.CurrentDispatcher from the back ground thread. What you need is the Dispatcher instance for the UI thread.
_worker.DoWork += delegate { DoWork(Dispatcher.CurrentDispatcher); };
...
private void DoWork(Dispatcher dispatcher) {
dispatcher.BeginInvoke(new Action(() => {
PartialEmployees.Clear();
});
}
I dont think you need the background work, as BeginInvoke on the Dispatcher runs on a Threadpool thread.
something like this should work, and is more succinct
DispatcherTimer dispTimer = new DispatcherTimer
{Interval = TimeSpan.FromSeconds(45)};
dispTimer.Tick += (o,e) => Dispatcher.CurrentDispatcher
.BeginInvoke((Action)PartialEmployees.Clear);
dispTimer.Start();
Can i create successfully a timer clock on a thread? i'm creating one but it doesn't seem to work that well. My app is a multi-thread app that has to start a timer on a thread when ever a certain event happens. The timer is placed in every client connection. The clock doesn't work until i close my winform(i don't know why) . Is there anything in particular that i should know about timers in threads ?
Here is my timer code :
timer1.Interval = 1000;
timer1.Tick += new EventHandler(timer_Tick);
timer1.Enabled = true;
timer1.Start();
You might try to use System.Threading.Timer, which is basically a timer that's in a separate thread. You might also consider using a WaitHandle that's never fired and then using WaitOne(1000, false) to wait for a second.
Try this:
public void EnableTimer()
{
if (this.InvokeRequired)
this.Invoke(new Action(EnableTimer));
else
this.timer1.Enabled = true;
}