I want to have a timer in my windows phone 8 app, that´s counting/running independent of current shown page.
It should connect to server - when possible in a UI independet task/thread - and store data in a global object/list.
The Independence from current shown page is my point.
I tried following in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
// timer interval specified as 1 minute
gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
But this doesn´t work. Than I tried just declaring the object in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
And on my startpage.xaml.cs:
// timer interval specified as 1 minute
App.gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
App.gAppTimer.Tick += OnTimerTick;
// starting the timer
App.gAppTimer.Start();
But this doesn´t work, too.
Any ideas how to handle my Problem? What I don´t want to use is a Background Task, because it runs only every 30 minutes. My solution should only run, if the app is "active" (in foreground).
That's normally done using a static or singleton class. Both will be global and you'll have access to them from every page.
Also, the DispatcherTimer invokes it's TimerTick method on the UI thread. If you don't need to be in the UI thread, you should use a System.Threading.Timer, which invokes a method in a background thread.
Here's an example:
public static class SomeManager {
private static Timer gAppTimer;
private static object lockObject = new object();
public static void StartTimer() {
if (gAppTimer == null) {
lock (lockObject) {
if (gAppTimer == null) {
gAppTimer = new Timer(OnTimerTick, null, 60 * 1000, 60 * 1000);
}
}
}
}
public static void StopTimer() {
if (gAppTimer != null) {
lock (lockObject) {
if (gAppTimer != null) {
gAppTimer.Change(Timeout.Infinite, Timeout.Infinite);
gAppTimer = null;
}
}
}
}
private static void OnTimerTick(object state) {
Action();
}
public static void Action() {
// Do what you need to do
}
}
Just call SomeManager.StartTimer() from your first page or from App.xaml.cs and the timer will start.
Update
I updated the code a little:
Renamed the Initialize method to StartTimer.
Added StopTimer method which stops the timer. You can then start it again by calling SomeManager.StartTimer.
Added Action method which is the one actually donig the work. You can invoke it from anywhere, anytime.
Note: the the timer will call this method in a background thread and you should do the same using something like Task.Run(() => SomeManager.Action());
Added a lock to ensure that the Start/Stop methods will not throw exceptions if invoked from multiple threads at the same time.
I'm not sure how you have arranged your code, but as I've tried:
public partial class App : Application
{
public static PhoneApplicationFrame RootFrame { get; private set; }
public DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
MessageBox.Show("TIMER fired");
}
public App()
{
gAppTimer.Interval = TimeSpan.FromSeconds(2);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
// rest of the code
the above code works. MessageBox shows every 2 seconds, if you had declared your DispatcherTimer as public, then you will be able to access it like this:
(App.Current as App).gAppTimer.Stop();
Note also that depending on what you want to achieve you may also use System.Threading.Timer.
On the other hand you may also think of using public static DispatcherTimer somewhere.
Related
I'm making a service. Among other things, it must read the value from registry and configure "Primary" timers' interval according to this value. Now it should do it not only in constructor phase, but also be able to change this interval when it has been changed in registry. How do I do that?
In other words, I have a code like this:
using System.Timers;
public static class GVARS
{
public static Config valFromRegistry = new ConfigRegistry().Result;
}
class Program
{
static void Main(string[] args)
{
int timerPeriod = (int)(uint)GVARS.valFromRegistry.Interval * 60000;
Timer primaryTimer = new Timer(timerPeriod);
primaryTimer.Interval = timerPeriod;
primaryTimer.Elapsed += RunPrimaryPayload;
primaryTimer.Start();
Console.ReadLine();
}
private static void RunPrimaryPayload(object sender, ElapsedEventArgs eventArgs)
{
SomeClass.SomeMethod(someArgs);
GVARS.valFromRegistry.Interval = (int)someNewValue;
}
}
Somewhere down the code I might change valFromRegistry.Interval and I want primaryTimer to respond to those changes. How do I get there?
PS. It's not really important to me how I'm gonna check for changes in registry, be it another timer or event. Whatever works.
PS2. I have a possible idea to use System.Threading.Timer for primaryTimer instead of System.Timers.Timer since the former has method Change() which I might call from another little configrationUpdateTimer every minute or so and make primaryTimer respond to configuration changes this way. Am I right?
Ok, I've managed to solve my problem by creating class with 2 Timers: one checking for config changes (master) and another (slave) is doing actual payload:
public class UniversalTimer
{
public System.Threading.Timer MasterTimer;
public System.Threading.Timer SlaveTimer;
private int lastMainTimerInterval = 0;
public UniversalTimer()
{
MasterTimer = new System.Threading.Timer(new System.Threading.TimerCallback(MasterTimerCallback), null, 0, 60000);
SlaveTimer = new System.Threading.Timer(new System.Threading.TimerCallback(SlaveTimerCallback), null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
}
private void MasterTimerCallback(object obj)
{
Log.Debug("[{0}:{1}:{2}] Re-reading configuration from registry", "Program", "UniversalTimer", "MasterTimerCallback");
var currentSettings = new ConfigRegistry().Result;
if ((int)currentSettings.Interval != lastMainTimerInterval)
{
Log.Debug("[{0}:{1}:{2}] Setting interval for Main Timer", "Program", "UniversalTimer", "SlaveTimerCallback");
lastMainTimerInterval = (int)currentSettings.Interval;
this.MainTimer.Change(0, (int)currentSettings.Interval * 60000);
}
}
private void SlaveTimerCallback(object obj)
{
Log.Debug("[{0}:{1}:{2}] Executing main cycle", "Program", "UniversalTimer", "SlaveTimerCallback");
}
public void Dispose()
{
MasterTimer.Dispose();
SlaveTimer.Dispose();
}
}
I am making a console application that will later be a Windows service application through Topshelf.
I am struggling with timers, I setup a timer with autoreset of 20 seconds. When I start the timer it works. And when I stop it it stops.
Now to the problem, I want to keep the value when stopping it.
I need an event handler as Timer offers. But I also need to have a way that remembers the time as Stopwatch does. Which should I choose? I have access to SQL server and save it.
Lets say I let it run for 10 seconds since autoreset is true, when I stop it. And then wait, and then start the timer again.
In my opinion, the next time I start the timer it should only run for 10 seconds. So the total time that fires up the event is 20 second and not 30.
Is there any way to "save" elapsed time on it?
public class MySampleClient
{
System.Timers.Timer BatchTimer;
public MySampleClient()
{
BatchTimer = new System.Timers.Timer(BatchSampleTimer) { AutoReset = true };
}
public async Task startSession()
{
BatchTimer.Elapsed += BatchTimerVoid;
}
public void BatchIDTrigger(BatchTagDataModel btdm)
{
string btdmValue = btdm.Value.ToLower();
if (batchNumberTimerControllerList.Contains(btdm.DisplayName))
{
if (btdmValue == "true")
{
BatchTimer.Start();
}
else
{
BatchTimer.Stop();
}
}
}
public void BatchTimerVoid(Object source, System.Timers.ElapsedEventArgs e)
{
// Something happens here every 20 seconds.
}
}
I have written a simple extension to a System.Timers.Timer to provide you with a Pause() method. It uses a backing System.Diagnostics.Stopwatch to modify the Timer.Interval according to the elapsed period before the pause.
public class ExtendedTimer: System.Timers.Timer
{
public long MillisecondsElapsed { get { return backingStopwatch.ElapsedMilliseconds; } }
public new double Interval { get; private set; }
private Stopwatch backingStopwatch;
public ExtendedTimer(double interval) : base(interval)
{
Interval = interval;
backingStopwatch = new Stopwatch();
base.Elapsed += ExtendedTimer_Elapsed;
}
private void ExtendedTimer_Elapsed(object sender, ElapsedEventArgs e)
{
base.Interval = this.Interval;
backingStopwatch.Restart();
}
public new void Start()
{
base.Interval = this.Interval - backingStopwatch.ElapsedMilliseconds;
base.Start();
backingStopwatch.Start();
}
public new void Stop()
{
base.Stop();
backingStopwatch.Reset();
}
public void Pause()
{
base.Stop();
backingStopwatch.Stop();
}
}
Since there is now some overhead introduced, I cannot speak to how accurately it will maintain precision timings compared to the original implementation.
I come from embedded C programming and I don't absolutely know anything about oop, task, threads, ecc..
I'm figuring out the basics concepts of C# and oop and wanted to try coding a simple stopwatch.
Goal: Toggle the stopwatch state with a button and show the value inside the button itself.
So far I've come to this:
namespace Cronometro
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MyTimerClass
{
private DateTime TimeValue;
private System.Timers.Timer TimerObj;
private const int TimeInterval = 1;
public MyTimerClass()
{
TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
TimerObj = new System.Timers.Timer(TimeInterval);
TimerObj.AutoReset = true;
TimerObj.Elapsed += TimerObj_Elapsed;
}
private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
}
public void Start()
{
TimerObj.Start();
}
public void Stop()
{
TimerObj.Stop();
}
}
}
Come to this point, I just wanted to print the value with Button.Content but seems like I cannot use it outside of the MainWindow class.
What should I do? I started thinking about creating a task inside the main class and wait for the timer event to print the value but I know nothing about threads and tasks.
It's unclear exactly what you mean, as at the moment you can't use it in the MainWindow class at all. Just expose the value via a public function, and you can fetch the instance's value anywhere you want.
namespace Cronometro
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var x = new MyTimerClass(); // <<<
x.Start(); // <<<
var timeValue = x.GetTimeValue(); // <<<
}
}
public class MyTimerClass
{
private DateTime TimeValue;
private System.Timers.Timer TimerObj;
private const int TimeInterval = 1;
public MyTimerClass()
{
TimeValue new DateTime(0, 0, 0, 0, 0, 0, 0, DateTimeKind.Local);
TimerObj = new System.Timers.Timer(TimeInterval);
TimerObj.AutoReset = true;
TimerObj.Elapsed += TimerObj_Elapsed;
}
private void TimerObj_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeValue = TimeValue.AddMilliseconds((double)TimeInterval);
}
public DateTime GetTimeValue() // <<<
{ // <<<
return TimeValue; // <<<
} // <<<
public void Start()
{
TimerObj.Start();
}
public void Stop()
{
TimerObj.Stop();
}
}
First, you don't have to write your own Stopwatch class. DotNet has its own:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.8
Second, try to understand async/await pattern:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
So, you can do something like this:
https://wouterdekort.com/2013/10/01/async-and-await-and-the-ui-thread/
One way you could populate the button text is you create an event in the MyTimerClass class, and attach a listener delegate to it from inside the MainWindow class.
Then, fire the event in TimerObj_Elapsed in MyTimerClass, so that the event handler in MainWindow will be called, and you will have a chance to populate the button.
However, there is something other than "practicing class" you have to deal with. Because you are using a thread pool timer, so the Elapsed event handler of the timer is invoked from a worker thread. In a GUI app, only the main / UI thread can interactive with controls. So chances are, you will get an exception when trying to set Button.Text. You will need to marshal the set action to the UI thread.
Frankly, if you are practicing writing classes in C#, I'd recommend you using a Console App to start with rather than a GUI app. It is probably not a good idea if people throwing out too many concepts on the table that you don't know at the same time.
Hi I have a similar problem to an old thread that I still can't work around
(Pass a return value back through an EventHandler) . I am eventually trying to implement a timer that will calculate velocity at even intervals so I require the Elapsed Time Event to return some kind of value. I've tried using global variables but the event doesn't seem to change the variable. Any advice? Thanks in advance!
namespace Timer_Label
{
public static class GlobalVariables
{
public static int _stringHolder;
public static int StringHolder
{
get { return _stringHolder; }
set { _stringHolder = value; }
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 500;
myTimer.Start();
MessageBox.Show(Convert.ToString(GlobalVariables.StringHolder));
}
public static void DisplayTimeEvent(object sender, ElapsedEventArgs e)
{
GlobalVariables.StringHolder = "1";
}
It's highly improbable that the timer will have expired by the time the code reaches your MessageBox.Show statement.
Try placing a Thread.Sleep(1000) call between myTimer.Start() and MessageBox.Show(). This should give the timer time to elapse and execute your DisplayTimeEvent handler.
Eventually, you will need to take into account the fact that the System.Timer.Timer class executes its callback in a background thread, so changes that you make in DisplayTimeEvent will need to be synchronized.
There's plenty of examples of people saying to use a Timer instead of Thread.Sleep(...) in an Azure Worker Role. No probs with that.
What I'm struggling to understand is how to code this.
Currently, I have the following (pseduo code)
_timer.Elapsed += (sender, args) => DoWork();
public override void Run()
{
while(true)
{
DoWork();
}
}
public void DoWork()
{
try
{
_timer.Stop();
// Now - do stuff ....
}
catch(....) { ... }
_timer.Start()
}
And what happens, is that the code enters the DoWork() method once and DoesStuff(tm).. fine .. starts the timer (say .. with a 30 second interval) and then exits that method.
Then, it returns back to the main Run() method .. which is in that loop. So it immediately comes back around and enters the DoWork() method again .. instead of waiting for the timer to fire it off.
So I'm not sure how to replace any Thread.Sleep(...) with Timers.
Any clues?
Clarification
I do not want to exit the Run() method :) I'm very happy to keep looping forever. What I'm stuck with, is replacing the standard Thread.Sleep(...) call (which blocks the thread) and replace that with a Timer, which most people suggest.
Update
Please do not link or suggest that I should use cancelSource.Token.WaitHandle.WaitOne(); as a solution. That is not what I'm trying to achieve here. Please note the post title!
I figure that if you want to solve this situation the way you outline here you will need a WaitHandle AND a Timer.
The short answer is here below. The long answer became a blog post: HowTo wait in a WorkerRole using Timer and EventWaitHandle over Thread.Sleep
I used an EventWaitHandle along with the Timer and came up with this solution:
public class WorkerRole : RoleEntryPoint
{
Waiter waiter;
public override bool OnStart()
{
waiter = new Waiter(WorkerConfiguration.WaitInterval);
return base.OnStart();
}
public override void Run()
{
while (true)
{
DoWork();
waiter.Wait();
}
}
public void DoWork()
{
// [...]
}
}
And here is the waiter class:
public class Waiter
{
private readonly Timer timer;
private readonly EventWaitHandle waitHandle;
public Waiter(TimeSpan? interval = null)
{
waitHandle = new AutoResetEvent(false);
timer = new Timer();
timer.Elapsed += (sender, args) => waitHandle.Set();
SetInterval(interval);
}
public TimeSpan Interval
{
set { timer.Interval = value.TotalMilliseconds; }
}
public void Wait(TimeSpan? newInterval = null)
{
SetInterval(newInterval);
timer.Start();
waitHandle.WaitOne();
timer.Close();
waitHandle.Reset();
}
private void SetInterval(TimeSpan? newInterval)
{
if (newInterval.HasValue)
{
Interval = newInterval.Value;
}
}
}