I have my winforms built in timer:
System.Windows.Forms.Timer timerLoop;
When the timer is started, I want (if possible) to pass this timer an integer value.
timerLoop.Start();
Till now, I only created a general variable that the timer can read and update this variable just before starting my timer.
You can do this two ways (maybe more):
Extend base Timer by creating new one that inherit it:
private class TimerExnteded : Timer
{
public int Value { get; set; }
public TimerExnteded(int value)
{
Value = value;
}
}
and use that value in Tick event.
Use Tag property of Timer
Timer t = new Timer();
t.Tag = 5;
t.Start();
//event
private void t_Tick(object sender, EventArgs e)
{
var timer = sender as Timer;
var value = (timer.Tag as int?) ?? 0;
value++;
timer.Tag = value;
}
Second approach uses boxing/unboxing of value.
You can also use closure:
t.Tick += (s, a) => OnTick(YourValue);
Related
I am having a class that has a timer, on timer elapsed I need to check a class level variable _isModelShutdown to determine whether to raise an event or not. The problem is that the timer is not able to get the latest value from the class level variable _isModelShutdown. I tried it by changing that variable to static variable, but that doesn't solve my problem, because this class is called by multiple threads. So, when I am in timer elapsed, the variable seems to get the default value of false instead of true which was set by an Consumer_Channel_ModelShutdown event saying shutdown happened. I think that another thread has already updated the static variable to false.
Workflow: When channel shutdown happens, Consumer_Channel_ModelShutdown is fired, that sets _isModelShutdown=true. Timer should check for _isModelShutdown==true to invoke Channel_Failure event. The reason why i can't do all this in the Consumer_Channel_ModelShutdown event is that RabbitMQ says shutdown callback is not a safe place to open another channel as it throws time out error on channel creation code. Hope this gives more clarity to the problem.
public class SomeClass
{
public event Func<string> Channel_Failure;
IModel consumerChannel = null;
private static bool _isModelShutdown = false;
public SomeClass(RabbitMQConnectionInfo rabbitMQConnectionInfo, Func<string> handleFailure)
{
if (handleFailure != null)
{
Channel_Failure = handleFailure;
}
consumerChannel = rabbitMQConnectionInfo.Connection.CreateModel();
// Some more code
if (connected) return;
StartTimer((int)reconnectionInterval);
}
private void StartTimer(int waitIntervalBeforeReconnecting)
{
double interval = 30000;
var retryTimer = new Timer(interval)
{
AutoReset = true //run once
};
retryTimer.Elapsed += (sender, eventArgs) =>
{
RetryTimerElapsed((Timer)sender);
}
retryTimer.Start();
}
private void RetryTimerElapsed(IDisposable sender)
{
if (_isModelShutdown) // This is the problem statement, how to access class level variable??
{
Channel_Failure?.Invoke(source);
_isModelShutdown = false;
}
}
private void Consumer_Channel_ModelShutdown(object sender, Client.ShutdownEventArgs reason)
{
_isModelShutdown = true;
}
}
Is there a better way to handle this scenario, any help would be appreciated.
public class PacketPoller
{
private Timer m_timer;
public void Start()
{
m_timer = new Timer(OnTick(null), null, 0, 1);
m_timer.InitializeLifetimeService();
}
public Action<Object> OnTick() { }
}
This is my code, however, the timer seems to require a staticmethod, rather than an object-oriented method. What can I do about it? I want to user to be able to create a new Timer and then change it's OnTick to set the method to call. How can I do that?
This is what I've successfully used recently.
DispatcherTimer timer1stDoze = new System.Windows.Threading.DispatcherTimer();
timer1stDoze.Tick += new EventHandler(timer1stDoze_Tick);
timer1stDoze.Interval = new TimeSpan(0, 5, 0);
timer1stDoze.Start();
If you're going to stick with the System.Threading.Timer, have it as you have, but have your PacketPoller have its own event that you'll fire in conjunction:
public class PacketPoller
{
public event EventHandler Tick;
private Timer m_timer;
public void Start()
{
m_timer = new Timer(OnTick, null, 0, 1);
m_timer.InitializeLifetimeService();
}
public void OnTick(object state)
{
var tick = this.Tick;
if (tick != null)
tick();
}
}
Listeners will be wired to your PacketPoller.Tick event rather than the m_timer directly. I'm assuming you don't have a state to bubble through, but if you need to you can pass it through. (notice I modified the method signature of OnTick and your constructor call as well)
I'm guessing that you are using the System.Timers.Timer class.
I would recommend trying with the System.Windows.Forms.Timer class instead. It do not require a static callback function and is a bit easier to work with (easier to debug due to it not being threaded).
This will require a reference to the System.Windows.Forms assembly tho.
timer.Tick += new EventHandler(CallbackFunction);
I have a windows form with a button.
I click the button and it starts a method in a separate class. I start this method in a separate thread.
When this class.method finishes it raises an event back to the windows form class.
When this happens I start another method in that separate class that tells a system.windows.form timer (declared in that class) to be enabled and thus start processing.
But the timer does not start (I did put a break point inside the 'tick' event).
I am assuming that it is because I declared the timer outside of the calling thread right at the start of my code.
Normally, I would use this to invoke a method on the same thread...
this.invoke(mydelegatename, any pars);
But, 'this' cannot be called with an class because unassumingly it is related to the UI thread.
I know this all looks bad architecture and I can easily solve this problem by moving the timer to the UI thread (windows form class).
But, I have forgotten how I did this many years ago and it really is an attempt to encapsulate my code.
Can anyone enlighten me pls?
Thanks
The Code:
[windows class]
_webSync = new WebSync(Shared.ClientID);
_webSync.evBeginSync += new WebSync.delBeginSync(_webSync_evBeginSync);
Thread _thSync = new Thread(_webSync.PreConnect);
_thSync.Start();
private void _webSync_evBeginSync()
{
_webSync.Connect();
}
[WebSync class]
private System.Windows.Forms.Timer _tmrManifestHandler = new System.Windows.Forms.Timer();
public WebSyn()
{
_tmrManifestHandler.Tick += new EventHandler(_tmrManifestHandler_Tick);
_tmrManifestHandler.Interval = 100;
_tmrManifestHandler.Enabled = false;
}
public delegate void delBeginSync();
public event delBeginSync evBeginSync;
public void PreConnect()
{
while (true)
{
if (some condition met)
{
evBeginSync();
return ;
}
}
}
public void Connect()
{
_tmrManifestHandler.Enabled = true;
_tmrManifestHandler.Start();
}
private void _tmrManifestHandler_Tick(object sender, EventArgs e)
{
//NOT BEING 'HIT'
}
You have to call _tmrManifestHandler.Start(); enabling is not enough.
Using a System.Windows.Forms.Timer on another thread will not work.
for more info look here.
Use a System.Timers.Timer instead, be carefull of CrossThreadExceptions if you are using accessing UI elements.
public class WebSync
{
private System.Timers.Timer _tmrManifestHandler = new System.Timers.Timer();
public WebSync(object id)
{
_tmrManifestHandler.Elapsed += new System.Timers.ElapsedEventHandler(_tmrManifestHandler_Tick);
_tmrManifestHandler.Interval = 100;
_tmrManifestHandler.Enabled = false;
}
public delegate void delBeginSync();
public event delBeginSync evBeginSync;
public void PreConnect()
{
while (true)
{
if (true /* just for testing*/)
{
evBeginSync();
return;
}
}
}
public void Connect()
{
_tmrManifestHandler.Enabled = true;
_tmrManifestHandler.Start();
}
private void _tmrManifestHandler_Tick(object sender, EventArgs e)
{
//NOT BEING 'HIT'
}
}
I have event handler:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
UpdateAnnotations();
}
Now I wish to update annotations only if user stopped scrolling, like if since last scrolling event passed 100ms, then execute action, else discard it, as it won't matter anyway.
What would be the easiest/reusable way to do that, preferably some static method like public static void DelayedAction(Action action, TimeSpan delay).
Using .NET 4.0.
See this answer to an Rx (Reactive Extensions) question. (You can use Observable.FromEvent to create an observable from an event.)
I would go with something like this
class MyClass
{
private System.Timers.Timer _ScrollTimer;
public MyClass()
{
_ScrollTimer= new System.Timers.Timer(100);
_ScrollTimer.Elapsed += new ElapsedEventHandler(ScrollTimerElapsed);
}
private void ResetTimer()
{
_ScrollTimer.Stop();
_ScrollTimer.Start();
}
private void Control_Scroll(object sender, ScrollEventArgs e, TimeSpan delay)
{
ResetTimer();
}
private void ScrollTimerElapsed(object sender, ElapsedEventArgs e)
{
_ScrollTimer.Stop();
UpdateAnnotations();
}
}
Every time the user scrolls, the timer gets reset and only when scrolling stops for 100ms the TimerElapsed gets fired and you can update your annotations.
I tried this with several controls on the form at the same time, and it is reusable by outside.
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
if (DelayedAction(100, sender))
UpdateAnnotations();
}
Dictionary<object, Timer> timers = new Dictionary<object, Timer>();
bool DelayedAction(int delay, object o)
{
if (timers.ContainsKey(o))
return false;
var timer = new Timer();
timer.Interval = delay;
timer.Tick += (s, e) =>
{
timer.Stop();
timer.Dispose();
lock(timers)
timers.Remove(o);
};
lock(timers)
timers.Add(o, timer);
timer.Start();
return true;
}
The dictionary is locked, because if a user cannot hit two controls at the same time, a timer might be inserted at the same time as another one is removed.
Try this class:
public class ActionHelper
{
private static Dictionary<Delegate, System.Threading.Timer> timers =
new Dictionary<Delegate, System.Threading.Timer>();
private static object lockObject = new object();
public static void DelayAction(Action action, TimeSpan delay)
{
lock (lockObject)
{
System.Threading.Timer timer;
if (!timers.TryGetValue(action, out timer))
{
timer = new System.Threading.Timer(EventTimerCallback, action,
System.Threading.Timeout.Infinite,
System.Threading.Timeout.Infinite);
timers.Add(action, timer);
}
timer.Change(delay, TimeSpan.FromMilliseconds(-1));
}
}
public static void EventTimerCallback(object state)
{
var action = (Action)state;
lock (lockObject)
{
var timer = timers[action];
timers.Remove(action);
timer.Dispose();
}
action();
}
}
Features:
Thead safe
Supports multiple concurrent actions
Usage:
private void Control_Scroll(object sender, ScrollEventArgs e)
{
ActionHelper.DelayAction(UpdateAnnotations, TimeSpan.FromSeconds(1));
}
Just be aware that the method is called in a separate thread. If you need to do UI work, you need to use Control.Invoke (WinForms) or Dispatcher.Invoke (WPF):
// The method is contained in a Form (winforms)
private void UpdateAnnotations()
{
if (this.InvokeRequired)
this.Invoke(new Action(UpdateAnnotations));
else
{
MessageBox.Show("Method is called");
}
}
Could you not store the time the event was fired (DateTime.Now) and when ever it's called check how long it's been since the last time (e.g. DateTime.Now - lastExecutionTime > minTime)
** Update **
Or a more generic way based on your static helper idea:
public static void DelayedAction(Action action, TimeSpan delay)
{
var delayedActionTimer = new Timer(x => action(), null, delay, TimeSpan.FromMilliseconds(-1));
}
Needs work obviously... for instance you could store the timer in a field and reset (change) the delay each time the user scrolls
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.