WPF Multiple Timer Control - c#

I searched a few links for Timer Control for both Windows and WPF applications but I would appreciate some advice on my situation...
As I'm using WPF it seems initial options are either System.Windows.Threading.DispatcherTimer or System.Diagnostics.Stopwatch
What I need to achieve is for each WPF DocumentPanel to request an update from an external API at a defined interval between typically 100ms Min - anytime Max with the interval unique to each DocumentPanel. Eg DP1 could be 100ms, DP2 could be 20,000ms etc.
Normally my app would start with 1 DocumentPanel but the user can expand panels without limit so it's the users judgement on CPU ability and speed of app.
Criteria include:
Multiple DocumentPanels - Typically 1 - 20 minimum but any advice on scalability is welcome.
Variable event interval (Iv) (Minimum event interval 100ms - Max < 1day)
Accuracy - 1ms (cannot have interval below (Iv)ms under ANY circumstances, over is not as much concern but needs to be be within several ms) EDIT: 1ms is not strictly a requirement but average (Iv) must be maintained over a short timescale.
Each DocumentPanel must display live date/time but produce events based on set interval
I'm really after help with design consideration rather than actual code at the moment as WPF is confusing matters for me.
Currently, I'm verging towards using a single instance of System.Diagnostics.Stopwatch and allow each panel to act on the stopwatch event whether the interval time has been reached.
Can anyone advise?
Thank you
O

its better to use just one System.Windows.Threading.DispatcherTimer with 100ms as ticks, then use Tags to determine its own interval, for example you can use
struct IntervalComparer
{
int myinterval; //the individual update interval (300ms for example)
int currentinterval;
public IntervalComparer(int myinterval)
{
this.myinterval=myinterval;
this.currentinterval=0;
}
public void TickMe()
{
currentinterval++;
}
public void ResetkMe()
{
currentinterval = 0;
}
public bool CanIUpdate()
{
return myinterval == currentinterval;
}
}
on the creation
.... Form_Loaded....
{
.....
mypanel=new Panel();
mypanel.Tag= new IntervalComparer(2); // 2 * 100ms
.....
}
.... Timer_Tick....
{
....
(mypanel.Tag as IntervalComparer).TickMe();
if((mypanel.Tag as IntervalComparer).CanIUpdate())
{
UpdateMyPanel();//your update method
(mypanel.Tag as IntervalComparer).ResetMe();
}
....
}

Generally in a case like this I would have a single timer which when then check for the elapsed time for each DocumentPanel. I'm guessing 100% accuracy is not critical, if they select 999ms then they won't notice if you main timer fires every 50ms so can only give them increments of 50ms. Windows does not give that sort of accuracy anyway, I learnt this when trying to trigger a flash once.

I've used the following approach to achieve something similar in a Silverlight app:
Single timer which ticks at a small interval (you're discretion, but would need to be lower than the lowest supported update interval), and then have each DocumentPanel subscribe to this timer's tick event.
When the tick event is fired, each DocumentPanel would then determine if an update is required based on it's update frequency (E.G. (last update - now ) > interval).
There's a comparison of some timer classes here:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
DispatcherTimer isn't mentioned, but the important difference between DispatcherTimer and System.Timers.Timer is:
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.
(from http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer.aspx).
Without knowing how you are currently handling UI updates and how you're program is structured, it's hard to say which timer you should use.
I'm not hugely familiar with the using the StopWatch, but my opinion is (after reading http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx) that using a single StopWatch isn't something that is particularly suited to this problem

use can inherit from DocumentPanel if you need the Tag property & for more encapsulation
class UpdatableDocumentPanel : DocumentPanel
{
public int myinterval { get; set; }//the individual update interval (300ms for example)
int currentinterval;
public void Update()
{
currentinterval++;
if (myinterval == currentinterval)
{
currentinterval = 0;
UpdateMyPanelMethod();
}
}
}
and
.... Form_Loaded....
{
.....
mypanel.myinterval = 2; // 2 * 100ms
.....
}
.... Timer_Tick....
{
....
mypanel.Update(); // simply
....
}

Related

Using C# async delays in Godot

I am currently experimenting with Godot C# making a basic shooter and for the gun's fire rate I have been experimenting with different delay systems. Node Timers work although I'm trying to make the script generic, and the Timer calls seem to only call functions in the parent script.
I'm now looking at C#'s Task.Delay method and it also seems to work, with it being an async action it does not look to be affected by the frame rate or slow down the game.
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Here's the code below although I don't think it’s important:
private void shoot() {
//if "canShoot" spawn bullet
ShootCooledDown();
}
private async void ShootCooledDown() {
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
canShoot = false;
await Task.Delay(span);
canShoot = true;
}
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Not per se. There is nothing in particular wrong with Task.Delay in games, nor too many instances of it.
However, what you are doing after Task.Delay can be a problem. If you execute await Task.Delay(span);, the code that comes after might run in a different thread, and thus it could cause a race condition. This is because of await, not because of Task.Delay.
For example, if after await Task.Delay(span); you will be adding a Node to the scene tree (e.g. a bullet), that will interfere with any other thread using the scene tree. And Godot will be using the scene tree every frame. A quick look at Thread-safe APIs will tell you that the scene tree is not thread-safe. By the way, the same happen with virtually any widget API out there.
The solution is use call_deferred (CallDeferred in C#) to interact with the scene tree. And, yes, that could offset the moment it happens to the next frame.
I'll give you a non threading alternative to do that.
There are method get_ticks_msec and get_ticks_usec (GetTicksMsec and GetTicksUsec in C#) on the OS class, that give you monotone time which you can use for time comparison.
So, if you make a queue with the times it should shoot (computed by taking the current time plus whatever interval you need). Then in your process or physics process callback, you can check the queue. Dequeue all the times that are overdue, and create those bullets.
If you don't want to solve this with Godot APIs, then start a Stopwatch at the start of the game, and use its elapsed time.
But perhaps that is not the mechanic you want anyway. If you want a good old cool-down, you can start the Stopwatch when you need the cool-down, and then compare the elapsed time with the cool-down duration you want to know if it is over.
I don't have any experience with Godot.. but my idea would be....
instead of using a timer, you could store the last shoottime in a variable/field. If you're trying to shoot within the lastTimeShot+coolDown, just ignore the shoot command.
For example:
private DateTime _lastShot = DateTime.MinValue;
private void shoot()
{
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
// if the time when the last shot has fire with the cooldown time
// is greater than the current time. You are still in the cooldown time.
if(_lastShot.Add(span) > DateTime.UtcNow)
return; // within cooldown, do nothing
//if "canShoot" spawn bullet
ShootCooledDown();
_lastShot = DateTime.UtcNow;
}
Due to a valid comment of Theodor, about changing the system time would lead bug-prone gameplay.
I wrote a second version.
private Stopwatch _shootingCooldownStopwatch = default;
private void shoot()
{
var shotDelayMs = shotDelay * 1000;
// if the _shootingCooldownStopwatch is ever started
// and the ElapsedMilliseconds are in the showDelay
// we're not allowed to fire again. So exit the method.
if (_shootingCooldownStopwatch?.ElapsedMilliseconds < shotDelayMs)
return;
_shootingCooldownStopwatch = Stopwatch.StartNew();
//if "canShoot" spawn bullet
ShootCooledDown();
}
I think this would be a better solution.
When you develop games in Godot or any other game engine, you shouldn't use any timer based in the computer clock, like the Stopwatch or Task.delay. Instead, you have to manage yourself the time elapsed using the delta time from the previous frame, which is received in the _Process(float delta) or _PhysicsProcess(float delta) methods. The reason are:
The time will be more accurate in case of frame-rate drop.
If you pause the game, timer will pause too.
That's the main reason Godot offers you a Timer component that you have to attach to the current scene in order to work with it.
If you don't want to add anything to the scene, which completely reasonable, you have to get the delta, storing the elapsed time in a variable and check if this variable reach some limit.
In my games, I use my own timers with this very simple class:
public class Timer {
public float Elapsed { get; private set; } = 0;
public bool Stopped { get; private set; } = true;
public float Alarm { get; private set; } = float.MaxValue;
public Timer Start() {
Stopped = false;
return this;
}
public Timer Stop() {
Stopped = true;
return this;
}
public Timer Reset() {
Elapsed = 0;
return this;
}
public Timer ClearAlarm() {
Alarm = float.MaxValue;
return this;
}
public Timer SetAlarm(float finish) {
Alarm = finish;
return this;
}
public bool IsAlarm() => Elapsed > Alarm;
public Timer Update(float delta) {
if (!Stopped) {
Elapsed += delta;
}
return this;
}
}
```
You have to Update the timer in every frame
I am no expert in Godot but I can tell that Task.Delay() is considered better than alternatives like Thread.Sleep() for example because being asynchronous i releases the thread to the thread pool and when the time has passed it continues execution, in contrast to the latter option that blocks the thread instead.
The problem I can see is that each web server can accept a max limit of concurrent requests, by using Task.Delay() in your code you can start accumulating requests "just waiting" due to the delay. So if your app starts receiving a big amount of requests coupled with a long Delay time that might be an issue with requests queued up (delay) or even denied.
If the delay is a number of seconds (significant time) then I would probably think about storing user in a cache (you can also store in a dictionary Dictionary<string, bool> where string is the userId but this solution will not scale out, that is why I suggest a distributed cache), and check (TryGetValue()) your cache if user is allowed to shoot. If delay is a couple of microseconds (affordable time) still not an ideal solution but it will probably be a problem.
In contrast to the answer by #Theraot and its approach via await Task.Delay(span) and according to my understanding, asynchronous does NOT equal to multi-threading. Using await Task.Delay(span) won't cause your code executing in another thread. So you don't really need to use CallDeferred in this case.
Reference:
What is the difference between asynchronous programming and multithreading?
Does Task delay create new Thread?
Does the use of async/await create a new thread?

Why Timer has no properties, how to get it's interval after initialization?

I'm using a System.Threading.Timer in my windows service for nightly import routines. It looks every minute into the database for new files to be imported. Now, since the service runs all day long, i want to change it so that it runs at night every minute and at day every 5th minute.
Therefore i thought i could check the current time, between 7am and 10PM use the day-interval-configuration value, otherwise the night-interval.
Now to the actual question: why is there no property in the Timer-class which indicates the current period/interval? Then i could decide whether i have to change it or not according to it's value.
As a workaround i could store it in an additonal field, but i wonder if it's possible to get the value from the timer itself.
Note that i'm using this constructor:
//start immediately, interval is in TimeSpan, default is every minute
importTimer = new System.Threading.Timer(
ImportTimer_Elapsed,
null,
TimeSpan.Zero,
Settings.Default.ServiceInterval_Night
);
Why is there no property in the Timer-class which indicates the current period/interval?
I assume (I'm not part of the .NET implementation team, so have to assume) this is because it used a Win32 Waitable Timer. And there is no API to get the settings of a Waitable Timer.
Note, if such properties did exit there would be a race condition:
Thread 1 reads the property and starts some business logic based on it
Thread 2 changes the property (invalidating thread 1's logic)
Thread 1 updates the property.
while any specific use of a timer may not suffer this, the general case has to cater for it.
(In Win32 this is even worse a WaitableTimer can be named, and thus accessed from other processes.)
You can use System.Timers.Timer instead, which provides such a property (".Intervall")
System.Threading.Timer does not have an internal field with the intervall value. I took a look into the .net code and i saw it isnt possible to get the current period by reflection.
Don't mess around with the tick rate. Instead invoke your code after a fixed number of ticks, depending on time:
private void ImportTimer_Elapsed(object o)
{
tickCount--;
if (tickCount <= 0)
{
// do your stuff
tickCount = Between7AMAnd10PM() ? 5 : 1;
}
}

C# program freezes using stopwatch to time an action

I have a Windows form program which controls a light. This light has its own class. I can do things like turn it on an off and change the color etc. This I can do without issue. What I want to be able to do, however, is make the light go on for a specific amount of time, i.e. 100 milliseconds or 300 milliseconds (depending on use).
I have tried to used stopwatch to do this, but when I click on the button that is meant to do this, it freezes the program. The light goes on, then doesn't turn off, and I can't use the stop button I have which is meant to turn it off.
The program loads the light, and initialises it, and displays an alert saying it has done this and detected one light. Then I use this:
private void Red_Click_1(object sender, EventArgs e)
{
//Displays Red
System.Threading.Tasks.Task.Factory.StartNew((Action)delegate()
{
displayRedDot();
});
}
This is the displayRedDot()
public void displayRedDot()
{
System.Diagnostics.Stopwatch clock1 = new System.Diagnostics.Stopwatch();
long elapsedTime = clock1.ElapsedMilliseconds;
clock1.Start();
while (elapsedTime < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
oBlynclightController.Display(BlynclightController.Color.Off);
clock1.Stop();
}
I have some other functions, which are identical this with a different time, which I haven't invoked anywhere yet because I can't get this to work.
Your code will never work since you are blocking the UI thread by busy waiting. This is the reason for your program seems to freeze. Use a timer or async/await instead
async void DisplayRedDot(int duration)
{
oBlynclightController.Display(BlynclightController.Color.Red);
await Task.Delay(duration);
oBlynclightController.Display(BlynclightController.Color.Off);
}
elapsedTime will never change its value. You initialize it right after creating the stopwatch, but never assign a new value to it. Stopwatch.ElapsedMilliseconds is a long. long is a value type. A copy is created and assigned to elapsedTime. You need:
while (clock1.ElapsedMilliseconds < 100)
{
oBlynclightController.Display(BlynclightController.Color.Red);
}
Note that this loop is going to run very quickly until that check returns false. Is this really what you want? I don't know exactly what your code is doing (you don't show us), but why not just set the color to red, wait 100ms, and then set it to... erm, Off.
It's also difficult for humans to pick up a change that only lasts 100ms. It's going to be a flicker at best.

How to trigger a timer tick programmatically?

Let's say I have a Windows Forms timer configured with a 10 second (10k ms) interval:
myTimer.Interval = 10000;
I want to start it and fire off the Tick event right away:
myTimer.Start();
myTimer_Tick(null, null);
The last line works but is there a better or more appropriate way?
The only thing I'd do differently is to move the actual Tick functionality into a separate method, so that you don't have to call the event directly.
myTimer.Start();
ProcessTick();
private void MyTimer_Tick(...)
{
ProcessTick();
}
private void ProcessTick()
{
...
}
Primarily, I'd do this as direct calling of events seems to me to be a Code Smell - often it indicates spagetti structure code.
There are at least 4 different "Timers" in .NET. Using System.Threading you can get one that specifically allows you to set the initial delay.
var Timer = new Timer(Timer_Elapsed, null, 0, 10000);
There are benefits to using the different timers and here is a good article discussing them all.
You could set the interval to 1 (0 probably means infinite timeout) and set it to 10k when it ticks for the first time.
The timer will tick "very soon" (depending what type of Timer you are using, see this) but the execution will not continue with the click handler as in your solution.
(I suppose you knew about the solution from Bevan).
Use two timers.
The First that has the normal interval you want to use and just enables the Second timer.
The Second timer has an interval of 100ms and is normally disabled. It runs your code and then disables itself.
To manually trigger, just enabled the Second timer.
This also allows you to trigger the code from another form using full qualification naming to the Second timer. I use this when calling from one form to another.

C# - Alternative to System.Timers.Timer, to call a function at a specific time

I want to call a specific function on my C# application at a specific time. At first I thought about using a Timer (System.Time.Timer), but that soon became impossible to use. Why?
Simple. The Timer class requires a Interval in milliseconds, but considering that I might want the function to be executed, let's says in a week that would mean:
7 days = 168 hours;
168 hours = 10,080 minutes;
10,080 minutes = 604,800 seconds;
604,800 seconds = 604,800,000 milliseconds;
So the interval would be 604,800,000;
Now let's remember that the Interval accepted data type is int, and as we know int range goes from -2,147,483,648 to 2,147,483,647.
That makes Timer useless, not in this case, but in the case of more than about 25 days, once we cannot set a Interval bigger that 2,147,483,647 milliseconds.
So I need a solution where I could specify when the function should be called. Something like this:
solution.ExecuteAt = "30-04-2010 15:10:00";
solution.Function = "functionName";
solution.Start();
So when the System Time would reach "30-04-2010 15:10:00" the function would be executed in the application.
How can this problem be solved?
Additional information: What will these functions do?
Getting climate information and based on that information:
Starting / Shutting down other applications (most of them console based);
Sending custom commands to those console applications;
Power down, rebooting, sleep, hibernate the computer;
And if possible schedule the BIOS to power up the computer;
EDIT:
It would seem that the Interval accepted data type is double, however if you set a value bigger that an int to the Interval, and call Start() it throws a exception [0, Int32.MaxValue].
EDIT 2:
Jørn Schou-Rode suggested using Ncron to handle the scheduling tasks, and at first look this seems a good solution, but I would like to hear about some who has worked with it.
Your "Start()" method should spawn a thread that wakes up at a defined interval, checks the time, and if you haven't reached the desired time, goes back to sleep.
I would recommend that you just write a program that deals with the business part of it and then execute that program when necessary by using Windows Task Scheduler.
One approach to task scheduling, simliar to that proposed by klausbyskov, is to built your scheduling service on top of an existing .NET scheduling framework/library. Compared to using the Windows Task Scheduler, this has the advantages of (a) allowing several jobs to be defined in the same project and (b) keeping jobs and scheduling logic "together" - i.e. not relying on server settings prone to get lost in system upgrades/replacements.
I know of two open-source projects that offer this kind of functionality:
"Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems." I have never actually used this framework myself, but from studying the website, I have the impression of a very solid tool, providing many cool features. The fact that there [quartz-net] tag on Stackoverflow might also indicate that it is actually used in the wild.
"NCron is a light-weight library for building and deploying scheduled background jobs on the .NET server platform." It does not have half as many features as Quartz.NET, and it does not have any tag on Stackoverflow, but the author (yours truly) believes that its low-friction API makes it somewhat easier to get started with.
Building your scheduling service on top of NCron, you can schedule a CleanupJob for weekly execution using a single line of code:
service.Weekly().Run<CleanupJob>();
Ok, you will need around three lines of boiler plate code on top of that to actually turn your project into a Windows service, but it sounds more impressive when I claim that it can be done with one line of code ;)
You could write some sort of wrapper class for a Timer which takes a DateTime instance. Then you perform the following steps:
Determine the difference between DateTime.Now and the desired time.
If the difference (in milliseconds) is larger than the maximum allowed value for the Timer.Interval property, set the Interval to the maximum allowed value (i.e. double.MaxValue or whatever) and start it.
Now, when the timer elapses the first time, you simply go back to step 1.
At some time, the difference will be smaller than the maximum allowed value for the Interval property, and then you could fire an event in your wrapper which ultimately calls the desired method.
Use the System.Threading.Timer:
var timer = new System.Threading.Timer(delegate { }, // Pass here a delegate to the method
null,
TimeSpan.FromDays(7), // Execute Method after 7 days.
TimeSpan.Zero);
You can use the System.Threading.Timer class, which provides a constructor accepting an interval expressed as an Int64, which should be enough for your needs.
Now for the other stuff :
You can start/stop/configure program using the Process class (I don't really get what you call "custom commands")
You cannot restart or shut down or control the local BIOS using native .NET classes. Rebooting / restarting is possible through Interop (calling native Windows API from .NET), and scheduling the BIOS is just impossible. Or maybe with a special server motherboard ? I don't know..
The class System.Threading.Timer has the same limitation too (it would throw an ArgumentOutOfRangeException according to MSDN).
There seems to be no .Net Framework class natively adept to circumvent the Int32.MaxValue milliseconds upper bound.
public static class Scheduler
{
private const long TimerGranularity = 100;
static Scheduler()
{
ScheduleTimer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
Tasks = new SortedQueue<Task>();
}
private static void Callback(object state)
{
var first = Tasks.Peek();
if(first.ExecuteAt<DateTime.Now)
{
Tasks.Dequeue();
var executionThread = new Thread(() => first.Function());
executionThread.Start();
}
}
private static Timer ScheduleTimer { get; set; }
public static void Start()
{
ScheduleTimer.Change(0, TimerGranularity);
}
public static void Add(Task task)
{
Tasks.Enqueue(task);
}
public static SortedQueue<Task> Tasks { get; set; }
}
public class Task : IComparable<Task>
{
public Func<Boolean> Function { get; set; }
public DateTime ExecuteAt { get; set; }
public int CompareTo(Task other)
{
return ExecuteAt.CompareTo(other.ExecuteAt);
}
}
The solution I'd use is something similar to the above example: a class Scheduler that manages all the Tasks (in order to avoid having a timer for each task we are going to schedule).
Tasks are added to the a queue able to perform sorted insertion. Note that SortedQueue<T> is not a type of the .Net Framework but an hypothetical, easy-to-code collection capable of sorted insertion on a comparable type T.
The scheduler awakes every TimerGranularity milliseconds and checks for the first task whose `ExecuteAt' time has been surpassed; then executes it on a separate thread.
Additional effort could be done by creating a list of all surpassed tasks (instead of the first one only); but I left it out for the sake of clarity.
There is exist exist nu-get called Quartz.NET.
You can use it exactly for this.

Categories