My WPF application involves several timers. Everything works with DispatcherTimers but the delays are huge and freezes occur often (for example 3 sec freeze then the remaining 3 sec get added at once).
My problem is i am not sure how exactly i have to redesign my application to get around this problem. Never worked with threads before and its my first real WPF application as well.
I get the following error:
The calling thread must be STA, because many UI components require this.
I got this error by replacing my Dispatcher timer by a Timer from the namespace System.Timers
Old code with dispatcher timer:
timerW = new DispatcherTimer();
timerW.Tick += new EventHandler(timerW_Tick);
timerW.Interval = new TimeSpan(0, 0, 5000);
timerW.Start();
New code with Timer:
timerW = new Timer();
timerW.Elapsed += new ElapsedEventHandler(timerW_Tick);
timerW.Interval = 5000;
timerW.Start();
A query gets executed every 5 seconds to retreieve a date value. When certain conditions are met buttons get dynamically created. For example if the date remains the same for 3 min a button gets created.
Dynamic created button contains:
Date from the database
A timer that starts running when the buttons gets created. This timer only stops when a new button gets created, this records the downtime.
A reason for the downtime
The buttons get saved in a ObservableCollection and use Dependency Properties so they get notified when something changes. It is a custom button with several textblocks to display the information.
The button part is where all the interaction is at in my program, the rest of the interface just displays information fro the database. The buttons get placed in a custom made slider like control with left and right navigation buttons.
So in short my program has 3 different dispatcher timers.
One to display the current time (hh:mm:ss format)
One to execute a sql query and retrieve a date value every 5 sec
One to update the downtime timer every second inside a dynamically custom styled WPF button. I use a stopwatch to record the downtime in between.
So it seems i need to work with treads and/or backgroundworker?
Not sure how i actually begin with this since i am pretty clue less for some time now. Some example code would be most welcome.
Tldr:
I use timers for the following reasons:
Display the current time
Record downtime (real time, so i actually see it counting by the second)
A SQL query that gets executed every 5 seconds.
EDIT:
public void InitializeDispatcherTimerW()
{
TimerCallback callback = MyTimerCallBack;
timerWegingen = new Timer(callback, null, 0, 5000);
timerWegingen.Change(0, 5000);
}
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
CaculateTimeBetweenWegingen();
}
Best regards,
Jackz.
System.Timers.Timer seems to require an STA thread. An STA thread was a requirement for Windows Forms, but WPF apparently doesn't need it.
Does System.Threading.Timer meet your need?
Here is an example:
// firstTickInterval and interval are TimeSpans
TimerCallback callback = MyTimerCallback;
Timer timer = new Timer(callback, null, firstTickInterval, interval);
// timer is now running
// To stop the timer, do timer.Change(-1, -1);
The callback function would look like this:
void MyTimerCallback(object state)
{
// This is not guaranteed to execute on the UI thread.
// In this example, state will be null, since we passed null in the Timer constructor.
}
When timers callback code interact with UI elements You need to use:
UIElement.Dispatcher.BeginInvoke(...);
More info: http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
Related
I have multiple timers running on my windows app. Each timer_tick runs a code. Right now I am working on two processes.
private async void tmrProcessDelay_Tick
private async void tmrAutopay_Tick
Just recently added the tmrAutopay as an added process so that instead of sequential process, I made them work at the same time. The problem I am having is that I am not able to restart the process of the Autopay.
Timers are declared at the top as an instance when form loads.
private System.Windows.Forms.Timer tmrProcessDelay = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer tmrAutopay = new System.Windows.Forms.Timer();
tmrAutopay.Interval = 2000;
tmrAutopay.Enabled = false;
tmrAutopay.Tick += new EventHandler(tmrAutopay_Tick);
private async void tmrAutopay_Tick(object sender, EventArgs e)
{
messagebox("tick"); // correcting this one
txtNotes.AppendText("tick");
tmrAutopay.Enabled = false;
// do some code
tmrAutopay.Enabled = true;
}
EDIT: as per Michael Randall suggestion, I tried adding break point at the top. I got the issue. Just on the logic. I just thought that it doesn't start again because "tick" only appends once, so I assumed it only ran once. When I went adding the break point, it ticked again, but for some reason, it did not appendText, reason I did assume things. Going back to the problem, due to the existing logic, after
called tick one - appendtext
enabled = true - ticked but did not append
due to logic, it did not go to enabled = true again
The timer tick only runs after I enabled it the first time, then when its ticks, I set it to false to do some code then start it again after finishing.
I have yet to try this system timer solution, and also saw some post that timers won't run on background process, since I can run it one time, it means it can.. But I just wanna ask before I change timers if there are any reasons why I am having this issue?
if you want to make like background process then you can do window service application and implement more than one timer in that code. I had good working experience with this type of application and I am confident that it will work without any issue with multiple timers. the only thing you need to be careful in code is that in case if some code takes longer than expected and more than timer interval then it will start another thread which could end up as deadlock for that timer or crash the application. Each timer works independently and creates a new thread each time when it ticks.
I have a Windows Forms application written in C# that does some automated testing. My test runs on the thread pool. The UI has a bunch of labels to display the data read from an external device. During the test, a method writes the new values to a singleton class. The singleton class broadcasts the value change and an event handler in the forms code does the updating after invoking on the UI thread. My problem is that it takes about 1.5 seconds just to update the UI (72 Labels). Why does it take so long? FYI, there is only one event broadcast for all 72 values, not one broadcast for each of the 72 values.
Here is the code (ProgramData.MaximumUnits = 18):
this.InvokeIfRequired(() =>
{
var stopwatch = new Stopwatch();
var rawData = TestData.Instance.RawDataDisplay;
stopwatch.Start();
for (int i = 0; i < ProgramData.MaximumUnits; i++)
{
Frequency1Label[i].Text = rawData[i].F1;
Frequency2Label[i].Text = rawData[i].F2;
TempSensorLabel[i].Text = rawData[i].T1;
UnitInfoLabel[i].Text = rawData[i].ErrorCode;
}
stopwatch.Stop();
MessageBox.Show(stopwatch.ElapsedMilliseconds.ToString());
});
The elapsed time is usually around 1500ms. I feel like this operation should be performed in less than 100ms.
Why this is a problem: I am displaying externally acquired data that comes in every 1 second. Since it takes 1.5 seconds to update the UI, I am in a serious bind, especially when the data can come in as fast as every half a second.
It's possible you're paying the cost of redrawing the form as you change the text of each label. You can try to freeze the form first, by calling SuspendLayout, make all of the changes to the different controls, and when you're done call ResumeLayout to redraw the whole screen at once.
e.g.
SuspendLayout();
try
{
// Update the labels
}
finally
{
ResumeLayout(performLayout: true);
}
Also, check if any of the labels have event handler(s) for the TextChanged event, as changing the text of the labels would trigger this event (and it could be doing something that is slowing you down).
Put the code into Form_load
try
{
ResumeLayout(performLayout: true);
}
finally
{
}
This.Refresh();
You have to This.Refresh() after the ResumeLayout Method Called
In relation to a previous question of mine ([question] : Which thread will timer method run in? ), I've added a Timer to my Windows Forms app to run every 100ms to show how long the program session has been running. I've defined it as follows (these are only the snippets relevant to the timer):
private System.Timers.Timer timerPureTime = new System.Timers.Timer(100);
timerPureTime.Elapsed += new System.Timers.ElapsedEventHandler(updateTimeElapsed);
this.timerPureTime.SynchronizingObject = currentForm; //where currentForm is my main Form
public void updateTimeElapsed(object sender, ElapsedEventArgs e)
{
if (currentForm.lblTimeElapsed.InvokeRequired) //lblTimeElapsed is your standard Windows Form label
{
currentForm.lblTimeElapsed.Invoke((MethodInvoker)delegate //also, trying to make make GUI invoking thread-safe here
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
});
}
else
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
}
purelyTime += 0.1;
}
As I understand it the Timer should be running in a thread of its own (taken from the Threadpool) however it still experiences some delay every now and then, throwing the timer off-course. Other threads within the application run pretty regularly (every 250ms) and computation-intensive, but shouldn't these be independent of Timer threads?
What could be the possible causes for timer lag in such cases?
Windows cannot guarantee a precisely regular callback for a timer, so you will definitely see that kind of variance.
You need to take a different approach:
Initialise a Stopwatch field in your class.
Call Stopwatch.Restart() when you want to reset the timing.
Inside updateTimeElapsed() use Stopwatch.Elapsed instead of purelyTime.
Note that your code is completely ignoring the amount of time spent in the timer handler function itself. Inside the handler, you are using Invoke to send a message to the UI and waiting for it to return. That can take an arbitrary amount of time, particularly if the UI is busy.
How to schedule the event, for instance I need to call a method which should perform its action for every given seconds. I'm developing simple windows form app, I tried using like
while(true)
{
methodToBeScheduled();
Thread.Sleep(60000);
}
This particular piece of code makes my application "Not-responding" while its executing. I hope timer can do this or any other logic that you experts suggest, kindly please let me know.
Thanks!
You can use the WinForms timer:
Timer _timer;
// In constructor (or anywhere you want to start the timer, e.g. a button event):
_timer = new Timer();
_timer.Interval = 60000; // milliseconds
_timer.Tick += (sender, e) => methodToBeScheduled();
_timer.Start();
This will cause methodToBeScheduled to be called once every 60 seconds, roughly. It will be called on the main UI thread, so avoid doing any heavy processing in it.
The advantage of using this timer is that it's built-in, doesn't require thread synchronization, and is simple to use. The disadvantage is that the interval is not exact -- the actual interval will vary depending on what other messages need to be processed in the application, and is also at the mercy of the Windows system clock, which is only accurate to 10-20ms or so.
You can use a Timer(System.Threading.Timer).
using System;
using System.Threading;
Timer _timer = null;
_timer = new Timer(o =>
{
methodToBeScheduled();
});
_timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(60));
Var sequence = Observable.interval(1).publish
Sequence.subscribe ....
Will allow to subscribe to an observable that will fire an onnext every second. See reactive extension ..
Hate typing on iPads....
Yes, there are three different types of timers (all of which are named Timer but behave a little different) in .net. The windows.forms timer executes a function at a certain rate--it calls the function from the UI thread. The System.Threading Timer does the same but calls the function from another thread. There is another timer that I can't remember off the top of my head. You will have to pick one of them based on your circumstance.
Threading timer is my favorite. Here is an example if how to use it. Just keep in mind whatever you are calling is not done from the UI thread. May want to use the forms timer or synchronize things if that's an issue.
In a Silverlight app, I have a block of code that has to run every 500ms. I am planning o use a DispatcherTimer to achieve this (see code below).
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 500); // 500 Milliseconds
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
However, it may happen that the block of code takes longer than 500ms to execute (the block of code does some webservice calls). How do I make sure that if a call is currently in progress, the DispatcherTimer doesn't trigger another event? What are the options and what is the best way? Using locks?
The DispatcherTimer only runs on the dispatcher thread - so there's no way you could have two handlers running at the same time. It's possible they'll be queued up and run one directly after another, of course - you should check.
However, you shouldn't be making a web service call in a DispatcherTimer anyway. Do it in a background thread, otherwise you're blocking the UI for updating all the time that you're waiting for the web service. Basically you shouldn't do any long-running work in the UI thread. Use one of the various other timers (e.g. System.Timers.Timer) to regularly perform work on a thread pool thread and use the dispatcher to call back to the UI thread when you've got some data which needs to be displayed on the UI.
Of course, now you've got the potential problem of the new kind of timer firing multiple times concurrently, on multiple threads. One option to avoid this is to set the AutoReset property to false, and just schedule the next timer tick at the end of the current one.
I would say you skip a tick if it takes too long, otherwise you will get a huge queue because of the lock.
So in the eventhandler say:
if(!busy) {
busy = true;
// some code which could take longer than 500 ms
busy = false;
}
In order make the event run successfull without getting a call from your DispatcherTimer again with in the previous tick completes stop the dispatcher timer after entering in to dt_Tick event and at the end of the tick event call the start again which will initializes the IsEnabled of DispatcherTimer again to true.
I don't know if DispatchTimer has any clever way to do this but what I would do in this situation is not to try to get the timer to not fire the event but to get the event to do nothing if it has not finished the previous run.
You can use locks to do this by getting a lock at the beginning of your event handler. If the lock is not available then exit the function (its already running) if you get the lock do the work and then once you've finished the work release the lock.
The method you want is Monitor.TryEnter and you'll want to make sure that you do your error trapping correctly as with any use of locks.