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.
Related
I got a little problem with my application.
I would like to update something on my UI every 10 seconds. I first used a DispatcherTimer for this but it will block my UI for a short time because the update method needs to load something from the web and this operation needs some time.
Now I thought about some kind of background worker and I found BackgroundTasks.
The problem with Background tasks is, as far as I understood it correctly, that they are supposed to serve as updaters even if the app is suspended. I don't need that.
I only would like to update if my app is running not if it is suspended.
Is there a good way to solve this?
Any suggestions what to use for this?
Thanks in advance!
You need two things for it:
Timer
You can update the UI in System.Timers.Timer with the 10 seconds interval.
Dispatcher
You need to use Dispatcher.Invoke to change the UI without holding the main UI thread. Instead the method Process should be called on a separate thread (Timer method), other than main UI thread, and use Dispatcher in it to alert main UI thread for the change.
Process() // method to be called after regular interval in Timer
{
// lengthy process, i.e. data fetching and processing etc.
// here comes the UI update part
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
}
You need to create a thread that runs the part of your code that gets and processes the information from the website. This way, your form will not hesitate because it will be on a different thread than the processing part.
This Article on code-project should get you started.
Also, you could start a timer, which has a elapsed event, that occurs every time the timer passes a certain time cycle.
http://www.dotnetperls.com/timer
The other answers are missing proper cleanup: When the timer fires in the exact moment that the window was closed, I would get an uncaught TaskCanceledException when trying to run Dispatcher.Invoke. I didn't find help for this problem in other questions. I was able to solve it by unregistering the timer callback when closing the window.
public partial class MainWindow : Window
{
Timer clockTimer = null;
public MainWindow()
{
clockTimer = new Timer(1.0); // 1 ms update to test for TaskCanceledException
clockTimer.Elapsed += Timer_Elapsed;
clockTimer.AutoReset = true;
clockTimer.Start();
Closed += (object sender, EventArgs e) => { clockTimer.Elapsed -= Timer_Elapsed; };
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e) {
var now = DateTime.Now;
Dispatcher.Invoke((Action)delegate () {
UpdateTime(now);
});
}
}
Obviously this is not a good idea if the window was re-shown. I tried adding a dtor, but it would never get called, probably due to cyclic dependencies.
Disclaimer: I don't know C#, so this might not be the best or proper way of doing things.
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
Can anybody suggest any reasons why a C# timer (created in a code-behind class) would stop without being told to?
My timer starts on page load and then stops when I click a button. I don't need to click the button for it to sometimes stop. IIS is not being restarted to my knowledge and no errors are being thrown either.
This is confusing me quite a bit...
Thanks.
// This gets called on page_load
private void checkTimer()
{
if (!parentTimer.Enabled) // If parent timer is not enabled then it is probably the start of a new day (after a night time server backup which kills timers)
{
parentTimer.Interval = 60000; // One minute
parentTimer.Elapsed += new ElapsedEventHandler(parentTimer_Elapsed); // Define what happens when elapsed
parentTimer.AutoReset = true; // Set timer to repeat
parentTimer.Enabled = true; // Start the timer
}
}
protected void btnCancel_Click(object sender, System.EventArgs e)
{
parentTimer.Stop();
...etc...
}
Note: I do not change ParentTimer at all in its elapsed method.
Basically ParentTimer governs a list of ChildTimers. If ParentTimer elapses it checks if one or more of the ChildTimers have elapsed too, if so, there is an event, if not then it resets the ChildTimer and carries on.
My suspicion is it's because the worker process for the page is stopping at the end of the request.
You could try increasing the request time out, but a better question is Can you explain why you're trying to do this ? What is the problem you're trying to solve ?
Remember, that regardless of all the fluff that ASP.Net puts around your code to make you feel comfortable (session state, viewstate etc), a web request is stateless and should be considered as a distinct pass of logic, it's not like a windows application where a background thread of code in your void Main(...) function is constantly running.
A timer is tied to the thread that created it and in the case of ASP.net the thread that handles each page request issued by a given user will change frequently due to the use of worker threads and the thread pool.
Using a timer at page-level simply won't work; you need to be tracking the state at Session-level (tied to the particular user) as your starting point.
In fact, I just wouldn't use timers at all in a web application, because their execution is simply not guaranteed.
If you're using this to run a background task - consider firing up your own worker thread in Application_Start or something like that. The thread will be terminated when the app pool recycles. You should also look at manually shutting the thread down the application is being shut down too.
Be careful with this, however, this thread can't assume it's always the only one running - due to IIS overlapped recycling, when a new one fires up the old one could still be running in the old AppDomain.
I have a timer event that fires every second. Sometimes when I exit the program (in the VS debugger), it tells me that the event thread is trying to access an object that no longer exists (because the main thread is over). I tried disabling the event before I exit (UpdateTime.aTimer.Enabled = false;). This cut down the number of times this problem occurs, but it still happens sometimes because the event fires before I can disable it.
Is this a serious problem? Will is haunt me if I don't deal with it?
If yes to the above, how do I kill it?
I ask the second question because I have no reference to the event thread, so I don't know how I can tell it to stop or wait for it to finish.
EDIT: More context. This is a Winform.
Also, I'm not explicitly creating a thread. It's my understanding that a thread is automatically created to handle events.
Creating the timer:
public static void Update(){
System.Timers.Timer aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true;
}
Event handler:
private static void OnTimedEvent(object source,ElapsedEventArgs e) {
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
}
Closing program handler:
private void Form1_FormClosing(object sender,FormClosingEventArgs e) {
aTimer.Enabled = false;
}
Serious Problem? Probably not, but I don't think a problem needs to be serious to need to be fixed. Warnings should be treated as errors in compilation, for example. In addition, if this is an app sent to clients, showing ugly errors on shutdown is not very professional.
How to solve this depends on how you are setting up the threads ("event thread" does not give enough info about the mechanics). One easy method might be to stall the main thread for a bit when the application shuts down until the threads all return. You have to also stop issuing new threads during this time.
Another possible solution would be to handle how the threads are created so you can shut down the process that fires them. Concepts like ThreadPool come to mind. Also ensuring threads are background threads, explicitly, can help in some situations.
The short answer is nobody will be able to give you a firm "this will fix your issue" answer without some context of what you are doing in your code.
ADDED:
There are a couple of "quick, down and dirty" ways to handle this. Don't have time for full analysis, so see if they work.
Just cure the error by waiting
Add a counter and wait until incremented down
The first thing I would consider is adding a safety net to not update the label when in a shutdown condition. That is regardless of anything else, as that is where your errors are firing. I don't think "main thread is not present" is the core of the issue, but rather this line:
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
How can you update something that no longer exists? Yes, it is on the main thread, so technically ...
A simple wait would be something like:
private void Form1_FormClosing(object sender,FormClosingEventArgs e)
{
aTimer.Enabled = false;
Thread.Sleep(5000);
}
Hiding the form is also not a bad idea, so the user does not see this?
If you want to use a more "COM like approach", you can add a counter. Increment on Update() (when the event is fired) and decrement on OnTimedEvent(). Make sure you lock the counter when changing it so you do not end up with two threads changing it at the same millisecond. You can then wait until the counter is 0 to finish form close or application unload.
Once again, these are quick, down and dirty, approaches, but they can save you from the error. I am sure someone with more time can come up with a more elegant solution.
You can close the window as suggested in MSDN - when you set the timer to be disabled during shutdown processing, set a flag that your Elapsed event handler can check to know that no more work is needed.
Elapsed events can occur after the
Dispose or Stop method has been called
or after the Enabled property has been
set to false, because the signal to
raise the Elapsed event is always
queued for execution on a thread pool
thread. One way to resolve this race
condition
is to set a flag that tells the event
handler for the Elapsed event to
ignore subsequent events.
Its hard to give a general awnser to the question if its serious or not, it depends entiry on what the timer is doing. what kind of timer is it? a system.Threading one or one of the UI timers?
If possible try and refactor your code so that you can tell the timer to stop firing, if only for the reason not to confuse the users with an error message. it could be as simple as sharing a variable or (preferably) using a CancellationToken
I just added some extra functionality to a Coding4Fun project. I have my project set up with an extra option to allow it to automatically change the background after X amount of time. X is set from a ComboBox. However, I know I've done this in a terrible way, as I have created a new timer class with System.Timers.Timer as a parent so when the static method in the ElapsedEventHandler is called, I'm able to get back to the form and call ChangeDesktopBackground().
What is a better way to call ChangeDesktopBackground() at a user defined interval?
Here is my current solution, which involves me casting the sender as my inherited timer, which then gets a reference to the form, which then calls the ChangeDesktopBackground method.
private static void timerEvent(object sender, System.Timers.ElapsedEventArgs e)
{
((newTimer)sender).getCycleSettingsForm().ChangeDesktopBackground();
}
Edit:Added coding sample to show current solution
I've written something like this before myself. System.Timers.Timer is overkill for this. You should probably use System.Windows.Forms.Timer, for a couple of reasons:
You're doing something that doesn't have to be too precise. The Windows timer is just a WM_TIMER message sent to your windows app's message pump, so you're not getting super great precision, but changing your wallpaper once a second is unrealistic. (I wrote mine to change every 6 hours or so)
When using a Windows Forms app that does some kind of timer-based task, you're going to run into all kinds of thread affinity issues if you go with System.Timers.Timer. Any Windows control has an affinity for the thread on which it was created, meaning that you can only modify the control on that thread. A Windows.Forms.Timer will do all that stuff for you. (For future nitpickers, changing wallpaper doesn't really count, cause it's a registry value change, but the rule holds generally)
Timers are probably the most straight-forward way of doing it, although I'm not sure you're using a timer correctly. Here's how I've used timers in my projects:
// here we declare the timer that this class will use.
private Timer timer;
//I've shown the timer creation inside the constructor of a main form,
//but it may be done elsewhere depending on your needs
public Main()
{
// other init stuff omitted
timer = new Timer();
timer.Interval = 10000; // 10 seconds between images
timer.Tick += timer_Tick; // attach the event handler (defined below)
}
void timer_Tick(object sender, EventArgs e)
{
// this is where you'd show your next image
}
Then, you'd connect your ComboBox onChange handler such that you'd be changing timer.Interval.
I would use Microsoft's Reactive Framework for this. Just NuGet "Rx-WinForms".
Here's the code:
var subscription =
Observable
.Interval(TimeSpan.FromMinutes(1.0))
.ObserveOn(this)
.Subscribe(n => this.getCycleSettingsForm().ChangeDesktopBackground());
To stop it just do subscription.Dispose().
Simple.