C# - Create setInterval / clearInterval functions - c#

I am new to C# and try to create a setInterval and clearInterval function which is exactly working like the same functions in javascript.
I do it mainly for practice and to learn what can be done in C# and what not.
setInterval
Requirements: Create a new timer and return it, also run a anonymous function or a predefined function again and again in the given interval.
Timer setInterval(Func<int> myMethod, int intervalInMs)
{
var timer = new Timer();
timer.Start();
while (true) { //probably a infinite loop
if (timer.ElapsedMilliseconds >= intervalInMs)
{
myMethod();
timer.Restart();
}
}
return timer; //Code does never reach this part obviously because of the while loop
}
clearInterval
Requirements: Stop the timer.
void clearInterval(Timer timer)
{
timer.Stop();
}
Planned Usage
Timer myTimer = setInterval(delegate {
MessageBox.Show(
"test",
"test",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
return 1;
}, 5000);
//somewhere in code...
clearInterval(myTimer);
How is it possible to solve this with C#, by using Events?

The .Net framework provides at least three different timers - System.Timers.Timer, System.Threading.Timer and System.Windows.Forms.Timer.
The System.Diagnostic.Stopwatch is not a timer and should not be used as one. It only measures how much time have passed between the Start() and Stop().
I would suggest using one of the timers provided by the .Net framework instead of re-inventing the wheel.
update
Well, since you insisted,
Here is a simple implementation NOT FOR USE IN PRODUCTION CODE since it's very easy to create memory leaks with it:
public static class Interval
{
public static System.Timers.Timer Set(System.Action action, int interval)
{
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (s, e) => {
timer.Enabled = false;
action();
timer.Enabled = true;
};
timer.Enabled = true;
return timer;
}
public static void Stop(System.Timers.Timer timer)
{
timer.Stop();
timer.Dispose();
}
}
You can see a live demo on rextester.

I managed to solve it by using events. It is maybe not the best solution, but as I already mentioned, I am a C# beginner.
Example:
This example shows a message box every 5000 ms, after three Messageboxes the interval is changed and at 10 boxes the interval is cleared. You can also stop the interval by pressing the button.
using System;
using System.Windows.Forms;
namespace Intervals
{
public partial class Form1 : Form
{
Interval ival1 = new Interval();
private int _A;
public int A
{
get { return _A; }
set {
_A = value;
if (value == 3) {
if (ival1 != null) {
MessageBox.Show(
"changeInterval Triggered",
A.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
ival1.changeInterval(1000);
}
}
if (value >= 10)
{
if (ival1 != null)
{
MessageBox.Show(
"clearInterval Triggered",
A.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
ival1.clearInterval();
}
}
}
}
public Form1()
{
InitializeComponent();
int interval = 5000;
ival1.setInterval(delegate {
A++;
MessageBox.Show(
A.ToString(),
"A",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
}, interval);
}
private void stopInterval_Click(object sender, EventArgs e)
{
ival1.clearInterval();
}
}
}
I created a new class Interval which is needed in order for this program to work.
using System;
namespace Intervals
{
public class Interval
{
private System.Timers.Timer timer;
private Action main;
public Interval()
{
timer = new System.Timers.Timer();
}
public void setInterval(Action pAction, int interval)
{
if (interval <= 0) { interval = 100; }
timer.Interval = interval;
main = new Action(delegate{
timer.Stop();
pAction?.Invoke();
timer.Start();
});
timer.Elapsed += (sender, e) => TimerEventProcessor(sender, e);
timer.Start();
}
public void changeInterval(int interval)
{
timer.Stop();
timer.Interval = interval;
timer.Start();
}
public void clearInterval()
{
main?.EndInvoke(null);
main = delegate
{
timer.Stop();
timer.Dispose();
};
}
public void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
main?.Invoke();
}
}
}
Memory Usage Test (260 Minutes):

Related

c# Memory on Nested Callbacks inside Action

So, i have this piece of code:
public void MovementTick()
{
if(MovementBehaviour != null)
{
MovementBehaviour.PerformMovement(this);
GameScheduler.Schedule(new SchedulerTask(MovementDelay)
{
Task = () =>
{
MovementTick();
}
});
}
}
This is to keep the scheduler running the monster tasks. However, since this is a nested call on MovementTick() will this cause memory problems somehow ? Is this code safe to use ? Should this be calling outside functions not to nest the MovementTick method ?
Would apreciate any help
Try using a timer tick event.
Timer timer { get; set; }
void Start ()
{
timer = new Timer();
timer.Interval = Timespan.FromMilliseconds(100);
timer.Elapsed +=TimerTick;
timer.Start();
}
void TimerTick(object o, EventArgs e)
{
MovementBehaviour?.PerformMovement(this);
}

C# wait timeout before calling method and reset timer on consecutive calls

I have a event in my code that can possibly get fired multiple times a second at some moment.
However I would like to implement a way to make that method wait 500ms before really firing, if the method gets called again before those 500ms are over, reset the timer and wait for 500ms again.
Coming from javascript I know this is possible with setTimeout or setInterval. However I'm having trouble figuring out how I could implement such a thing in C#.
You could use a System.Timers.Timer wrapped in a class to get the behaviour you need:
public class DelayedMethodCaller
{
int _delay;
Timer _timer = new Timer();
public DelayedMethodCaller(int delay)
{
_delay = delay;
}
public void CallMethod(Action action)
{
if (!_timer.Enabled)
{
_timer = new Timer(_delay)
{
AutoReset = false
};
_timer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
action();
};
_timer.Start();
}
else
{
_timer.Stop();
_timer.Start();
}
}
}
This can then be used in the following manner:
public class Program
{
static void HelloWorld(int i)
{
Console.WriteLine("Hello World! " + i);
}
public static void Main(string[] args)
{
DelayedMethodCaller methodCaller = new DelayedMethodCaller(500);
methodCaller.CallMethod(() => HelloWorld(123));
methodCaller.CallMethod(() => HelloWorld(123));
while (true)
;
}
}
If you run the example, you will note that "Hello World! 123" is only displayed once - the second call simply resets the timer.
If you need to reset the timer when the method is called again, consider looking at the ManualResetEvent class:
https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx
You can use this to notify one or more waiting threads that an event has occurred.
You can use Thread.Sleep() with locking
private object locking = new object();
lock (locking )
{
Thread.Sleep(500);
//Your code to run here
}
https://msdn.microsoft.com/en-us/library/system.threading.thread.sleep(v=vs.110).aspx
Just writen super simple class with System.Threading.Thread; With a little different approach Usage.
var delayedCaller = new DelayedTimeout(() => HelloWorld(123), 500, false);
delayedCaller.ResetTimer();
delayedCaller.ResetTimer();
Currently, you can do it very simple with the following class
public class DelayedTimeout
{
readonly Timer _timer;
readonly int _timeoutMs;
public DelayedTimeout(TimerCallback callback, int timeoutMs, bool startNow)
{
_timeoutMs = timeoutMs;
// Should we start now
var currentTimeoutMs = startNow ? _timeoutMs : Timeout.Infinite;
_timer = new Timer(callback, null, currentTimeoutMs, Timeout.Infinite);
}
// Constructor overloading
public DelayedTimeout(Action callback, int timeoutMs, bool startNow) :
this(delegate (object? obj) { callback.Invoke(); }, timeoutMs, startNow)
{}
public void ResetTimer()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // Stop the timer
_timer.Change(_timeoutMs, Timeout.Infinite); // Stop the timer
}
}

Using a timer, how to run a function from another user control when the time elapsed

I have a WPF user control called TimerUserControl where contains a timer. And I have another user control where show questions, this one has a NextQuestion function.
The timer has 2 minutes like an interval, and I'd like to invoke the NextQuestion function when it has done. I think I have to use delegates, but I'm not sure.
UPDATE 1:
public partial class TimeUserControl : UserControl
{
public int _totalSeconds;
public int _secondsRemaining;
public DispatcherTimer timerSecondsLeft;
public TimeUserControl()
{
InitializeComponent();
timerSecondsLeft = new DispatcherTimer();
timerSecondsLeft.Tick += new EventHandler(timerSecondsLeft_Tick);
timerSecondsLeft.Interval = new TimeSpan(0, 0, 1);
}
public bool TimesUp
{
get;
set;
}
public void SetSeconds(int seconds)
{
timerSecondsLeft.Stop();
if (seconds == 0)
{
TimeTextBlock.Text = "There's no time! Hurray";
}
else
{
_totalSeconds = seconds;
_secondsRemaining = seconds;
TimeTextBlock.Text = string.Format("It remains {0} seconds. Don't take long!", _totalSeconds);
timerSecondsLeft.Start();
}
}
public void timerSecondsLeft_Tick(object sender, EventArgs e)
{
_secondsRemaining--;
if (_secondsRemaining <= 0)
{
timerSecondsLeft.Stop();
TimesUp = true;
TimeTextBlock.Text = "Time's up. Press Enter to next problem.";
// HERE WILL INVOKE NEXTQUESTION FUNCTION
}
else
{
TimeTextBlock.Text = string.Format("It remains {0} seconds. Don't take long!", _secondsRemaining);
}
}
}
Look in the code, the comment is this possible ussing delegates?
So you need to do a few things. You have to add some code to you're user control.
// Declare this outside your usercontrol class
public delegate void TimerExpiredEventHandler(object sender, EventArgs e);
This is what needs to be added to your code for the user control.
public partial class TimerUserControl : UserControl
{
public event TimerExpiredEventHandler Expired;
public void OnExpired(EventArgs e)
{
if (Expired != null)
Expired(this, e);
}
public void timerSecondsLeft_Tick(object sender, EventArgs e)
{
_secondsRemaining--;
if (_secondsRemaining <= 0)
{
timerSecondsLeft.Stop();
TimesUp = true;
TimeTextBlock.Text = "Time's up. Press Enter to next problem.";
// Fire the event here.
OnExpired(EventArgs.Empty);
}
else
{
TimeTextBlock.Text = string.Format("It remains {0} seconds. Don't take long!", _secondsRemaining);
}
}
}
Now you need to subscribe to this event inside whatever is calling this usercontrol in the first place.
public partial class ParentForm : Form
{
private void ParentForm_Load(object sender, EventArgs e)
{
var timer = new TimerUserControl();
//Subscribe to the expired event that we defined above.
timer.Expired += new EventArgs(Timer_Expired);
}
public void Timer_Expired(object sender, EventArgs e)
{
//Handle the timer expiring here. Sounds like you are calling another function, so do that here.
}
}
Use the TreeHelper to hunt up the tree for a shared Parent and then down the tree for the User Control you want. Something like this pseudo code:
this.Timer = new System.Windows.Threading.DispatcherTimer
{
Interval = new TimeSpan(0, 0, 1)
};
this.Timer.Tick += (s, e) =>
{
var _Control = s as MyFirstControl;
var _Other = LogicalTreeHelper.GetChildren(_Control.Parent)
.Cast<FrameworkElement>().Where(x => x.Name == "FindIt")
.First<MySecondControl>();
_Other.DoMethod();
};
Best of luck!
i would probably break out the functionality of the timer control here; something like this (note: i am writing this on-the-fly so let me know if it doesn't work as-is, and i will help correct any issues):
// a simple delegate to report the amount of time remaining
// prior to the expiration of the major tick interval; zero
// indicates that this major tick has elapsed.
public delegate void delegateMajorMinorTimerTick
(
int TimeRemaining_sec, ref bool CancelTimer
);
// you could use milliseconds for the interval settings to get
// better granularity, or you could switch to setting the major
// interval instead, however that approach would require a bit
// more checking to make sure the control has sane settings.
public class MajorMinorTimer
{
// this sets the interval in seconds between the
// "minor" ticks used for intermediate processing
// these are the "inner" intervals of the timer
private int myMinorTickInterval_sec;
public int MinorTickInterval_sec
{
get { return myMinorTickInterval_sec; }
}
// this sets the number of minor ticks between the
// expiration of the major interval of the timer.
// the "outer" interval of the timer
private int myMinorTicksPerMajorTick;
public int MinorTicksPerMajorTick
{
get { return myMinorTicksPerMajorTick; }
}
public MajorMinorTimer
(
int parMinorTickInterval_sec,
int parMinorTicksPerMajorTick
)
{
MinorTickInterval_sec = parMinorTickInterval_sec;
MinorTicksPerMajorTick = parMinorTicksPerMajorTick;
}
private DispatcherTimer myBackingTimer;
private int myMinorTickCount;
public void Start()
{
// reset the minor tick count and start the dispatcher
// timer with some reasonable defaults.
myMinorTickCount = 0;
myBackingTimer =
new DispatcherTimer
(
TimeSpan.FromSeconds(MinorTickInterval_sec),
DispatcherPriority.Normal,
new EventHandler(myBackingTimer_Tick),
Dispatcher.CurrentDispatcher
);
myBackingTimer.Start();
}
public event delegateMajorMinorTimerTick onTick;
private bool FireMajorMinorTimerTick(int TimeRemaining_sec)
{
// allows the timer sink to cancel the timer after this
// call; just as an idea, also could be handled with a
// call to Stop() during the event, but this
// simplifies handling a bit (at least to my tastes)
bool CancelTimer = false;
if (onTick != null)
onTick(TimeRemaining_sec, ref CancelTimer);
return CancelTimer;
}
private void myBackingTimer_Tick(object Sender, EventArgs e)
{
// since we are using a DispatchTimer with settings that should
// do not suggest the possibility of synchronization issues,
// we do not provide further thread safety. this could be
// accomplished in the future if necessary with a lock() call or
// Mutex, among other methods.
++myMinorTickCount;
int TicksRemaining = myMinorTickCount - MinorTicksPerMajorTick;
bool Cancel =
FireMajorMinorTimerTick(TicksRemaining * MinorTickInterval_sec);
if (TicksRemaining == 0)
myMinorTickCount = 0;
if (Cancel)
Stop();
}
public void Stop()
{
myBackingTimer.Stop();
}
}
then, assuming, say, a Quiz control, the timer is used like so:
public void QuestionTimerSetup()
{
// sets up a timer to fire a minor tick every second
// with a major interval of 5 seconds
MajorMinorTimer timerQuestion = new MajorMinorTimer(1, 5);
timerQuestion.onTick +=
new delegateMajorMinorTimerTick(QuestionControl_QuestionTimerTick);
}
// ...
public void QuestionControl_OnTick(int TimeRemaining_sec, ref bool CancelTimer)
{
if (TimeRemaining_sec > 0)
{
tblockQuizStatus.Text =
string.Format("There are {0} seconds remaining.", TimeRemaining_sec);
}
else
{
// just for an example
if (NoMoreQuestions)
{
CancelTimer = true;
HandleEndOfQuiz();
tblockQuizStatus.Text =
"Time's up! The quiz is complete!";
}
else
{
tblockQuizStatus.Text =
"Time's up! Press Enter to continue to the next problem.";
}
}
}
another option (rather than, or in addition to, events) in implementing this might be to add an Action taking the time remaining in the major interval for the minor interval action, an Action for the major interval action, and a Func<bool> that checks the stop condition, allowing the user to perform the desired actions in that way. like this:
public class MajorMinorTimer
{
public MajorMinorTimer
(
int parMinorTimerInterval_sec,
int parMinorTicksPerMajorTick,
Action<int> parMinorTickAction,
Action parMajorTickAction,
Func<bool> parShouldStopFunc
)
{
myMinorTimerInterval_sec = parMinorTimerInterval_sec;
myMinorTicksPerMajorTick = parMinorTicksPerMajorTick;
myMinorTickAction = parMinorTickAction;
myMajorTickAction = parMajorTickAction;
myShouldStopFunc = parShouldStopFunc;
}
private Action<int> myMinorTickAction;
private Action myMajorTickAction;
private Func<bool> myShouldStopFunc;
private void myBackingTimer_OnTick()
{
++myMinorTickCount;
int TicksRemaining = myMinorTickCount - MinorTicksPerMajorTick;
if (TicksRemaining == 0)
myMajorTickAction();
else
myMinorTickAction(TicksRemaining * MinorTickInterval_sec);
bool Cancel = myShouldStopFunc();
if (TicksRemaining == 0)
myMinorTickCount = 0;
if (Cancel)
Stop();
}
}
and then in the quiz code instead of hooking up the event do something like:
public void QuestionTimerSetup()
{
MajorMinorTimer timerQuestion =
new MajorMinorTimer
(
1,
5,
// major interval action
(SecsRemaining) =>
{
tblockQuizStatus.Text =
string.Format
(
"There are {0} seconds remaining.", SecsRemaining
);
},
// minor interval action
() =>
{
if (NoMoreQuestions)
{
tblockQuizStatus.Text =
"Time's up! This completes the quiz!";
HandleEndOfQuiz();
}
else
{
tblockQuizStatus.Text =
"Time's up! Press Enter to continue to next question.";
}
},
// timer cancel check function
() =>
IsEndOfQuizHandled()
);
}

raising events in C# and outputting?

ive been working on a program. i has 3 classes. 2 of the classes have timers that repeat at different intervals and once one "cycle" of the timer is done it raises an event with a string as return. the 3rd class subscribes to the events from the other two timer classes and prints them to screen. it works great!
but my issue is that it prints them separately. say currently the first timer class runs and then raises "hello" every 2 minutes and the other class "dog" every second. then every time an event is raised it prints the raised event to console. i would want it to instead print "hellodog" every second.
i was thinking: so each time a timer fires it will raise an event and update a string in the "output" class with the current value, then make another timer that goes off every second, this timer will read both the updated strings together as one output like "hellodog". is this possible if it is this is the easiest way i think. how would i achieve this idea?
if it is confusing i will clarify.
namespace Final
{
public class Output
{
public static void Main()
{
var timer1 = new FormWithTimer();
var timer2 = new FormWithTimer2();
timer1.NewStringAvailable += new EventHandler<BaseClassThatCanRaiseEvent.StringEventArgs>(timer1_NewStringAvailable);
timer2.NewStringAvailable += new EventHandler<BaseClassThatCanRaiseEvent.StringEventArgs>(timer2_NewStringAvailable);
Console.ReadLine();
}
static void timer1_NewStringAvailable(object sender, BaseClassThatCanRaiseEvent.StringEventArgs e)
{
var theString = e.Value;
//To something with 'theString' that came from timer 1
Console.WriteLine(theString);
}
static void timer2_NewStringAvailable(object sender, BaseClassThatCanRaiseEvent.StringEventArgs e)
{
var theString2 = e.Value;
//To something with 'theString2' that came from timer 2
Console.WriteLine(theString2);
}
}
public abstract class BaseClassThatCanRaiseEvent
{
public class StringEventArgs : EventArgs
{
public StringEventArgs(string value)
{
Value = value;
}
public string Value { get; private set; }
}
//The event itself that people can subscribe to
public event EventHandler<StringEventArgs> NewStringAvailable;
protected void RaiseEvent(string value)
{
var e = NewStringAvailable;
if (e != null)
e(this, new StringEventArgs(value));
}
}
public partial class FormWithTimer : BaseClassThatCanRaiseEvent
{
Timer timer = new Timer();
public FormWithTimer()
{
timer = new System.Timers.Timer(200000);
timer.Elapsed += new ElapsedEventHandler(timer_Tick); // Everytime timer ticks, timer_Tick will be called
timer.Interval = (200000); // Timer will tick evert 10 seconds
timer.Enabled = true; // Enable the timer
timer.Start(); // Start the timer
}
void timer_Tick(object sender, EventArgs e)
{
...
RaiseEvent(gml.ToString());
}
}
public partial class FormWithTimer2 : BaseClassThatCanRaiseEvent
{
Timer timer = new Timer();
public FormWithTimer2()
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Tick2); // Everytime timer ticks, timer_Tick will be called
timer.Interval = (1000); // Timer will tick evert 10 seconds
timer.Enabled = true; // Enable the timer
timer.Start(); // Start the timer
}
void timer_Tick2(object sender, EventArgs e)
{
...
RaiseEvent(aida.ToString());
}
}
}
You can use the same event handler for both timers. And construct the output by identifying the senders. (Didn't test the code for syntax errors.)
private static string timer1Value = string.Empty;
private static string timer2Value = string.Empty;
private static FormWithTimer timer1;
private static FormWithTimer2 timer2;
public static void Main()
{
timer1 = new FormWithTimer();
timer2 = new FormWithTimer2();
timer1.NewStringAvailable += new EventHandler<BaseClassThatCanRaiseEvent.StringEventArgs>(timer1_NewStringAvailable);
timer2.NewStringAvailable += new EventHandler<BaseClassThatCanRaiseEvent.StringEventArgs>(timer1_NewStringAvailable);
Console.ReadLine();
}
static void timer1_NewStringAvailable(object sender, BaseClassThatCanRaiseEvent.StringEventArgs e)
{
if (sender == timer1)
{
timer1Value = e.Value.ToString();
}
else if (sender == timer2)
{
timer2Value = e.Value.ToString();
}
if (timer1Value != String.Empty && timer2Value != String.Empty)
{
Console.WriteLine(timer1Value + timer2Value);
// Do the string concatenation as you want.
}
When the events are handled in your example they have no access to information about the other events. If you want to have 2 events that update strings, but you want the handler to print data from both updated strings, you need the event handlers to have access to both of those strings. You can either store them in variables on the event handling class, or make them public properties of the classes that are raising the events. That way in either event handler you have access to the updated strings from other events.

Interested In Feedback About My Timeout Class

Many areas in a project I'm working on have a simple timeout check which basically runs code through a try loop until it succeeds or 10 seconds elapses.
class Timeout {
private readonly DateTime timeoutDate;
public bool FlagSuccess;
public Timeout() {
timeoutDate = DateTime.UtcNow.AddSeconds(10);
flagSuccess = false;
}
public bool continueRunning() {
if (!flagSuccess && DateTime.UtcNow < timeoutDate) return true;
else return false;
}
}
Here is an example of the class in use:
Timeout t = new Timeout();
while (t.continueRunning()) {
try {
//PUT CODE HERE
t.flagSuccess = true;
}
catch(Exception e) {
Console.WriteLine(e.Message);
}
}
Before I implement this, is there a better and more standard way to do this? What I have above is based on my blind intuition.
Use .NETs Timer class(es):
using System.Timers;
public static void Main() {
Timer t = new Timer();
t.Elapsed += new ElapsedEventHandler(ActionWhenFinished);
t.Interval = 10000;
t.Start();
}
public static void ActionWhenFinished()
{
// cancel any action
}
Your Timeout class will block the current thread it is running in, which isn't the case with System.Timer.
I'd suggest changing your loop to a do-while loop, so that you're guaranteed to run the loop at least once even if your thread gets momentarily waylaid between setting up the timeout and starting the loop. Also, I'd suggest that it may be helpful to have the Timeout class include a RemainingMilliseconds property, and maybe RemainingMillisecondsUpTo(Integer N) function, which could be passed to various block-or-timeout routines.
Looks kind of like a busy loop to me, but here's how you'd do it with a StopWatch.
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
bool complete;
while( timer.ElapsedMilliseconds < 10000 && !complete)
{
//Do stuff
// and someday... complete = true;
}
You could wrap that up into a simple class as well if you like.
class AgingWait
{
System.Diagnostics.Stopwatch _watch = new System.Diagnostics.Stopwatch();
int maxMilliseconds;
bool forceExpire;
public bool Expired
{
get { return forceExpire || maxMilliseconds < _watch.ElapsedMilliseconds; }
}
public AgingWait(int milli)
{
_watch.Start();
maxMilliseconds = milli;
}
public void Expire()
{
forceExpire = true;
}
}
to use
AgingWait waiter = new AgingWait(1000);
while (!waiter.Expired)
{
if (condition)
waiter.Expire();
}

Categories

Resources