Timer Sequence is Increasing On each go - c#

So I am making a Robbery system the timer works perfectly on the first start the sequence by the timer goes down is 10,9,8,7...... But on the 2nd try the sequence is 10,8,6,4...... on the 3rd try its 10,7,4,1..... Etc meaning on each start the timer sequence increase the decrease time? How is it possible? Can you make an edit on the code for me?
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
cd.Elapsed += (source, e) => OnTimer(player);
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
cd.Elapsed -= (source, e) => OnTimer(player);
}
but when i use (cd1.Elapsed += (Object source, ElapsedEventArgs e, User player) on OnTimer it gives me an error on the cd.Elapsed -= (source, e) => OnTimer(source, e, player); Line stating local variable is source cannot be used here as it is defined in this scope

I suspect this is because your elapsed event handler isn't actually being removed, so it is firing multiple times at each tick.
The following question/answer discusses how to remove a delegate, and how Delegate.Equals determines which delegate gets removed (if any): C# removing an event handler
However, you are not removing the same handler, you are creating two separate lambda functions that perform exactly the same task within different contexts. .NET isn't very good at collapsing duplicate code - it cannot resolve that your second lambda is the same as your first because they are each created in a different scope, and therefore each has a different closure (the saved image of all visible variables within the scope where it is created).
If you create an actual non-lambda method, and then use delegates rather than lambdas, this problem should go away. Or, you may be able to assign the lambda to a variable that is accessible to both functions (without modifying it in between).

This is a example implementation of Matt Jordan's solution "assign the lambda to a variable that is accessible to both functions"
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
ElapsedEventHandler handler = null;
handler = (source, e) => OnTimer(player, handler);
cd.Elapsed += handler;
cd.Start();
}
public void OnTimer(User player, ElapsedEventHandler handler)
{
cd.Stop();
cd.Elapsed -= handler;
}
Because lambadas capture variables, not values, handler can reference itself so long as it is already been initialized to a value (null in this example) before you try to use it.

Related

Is there a way to use one Timer for multiple events?

I am in C# .NET 3.5
What happens when timer elapses and event handler is performed ?
Does the timer cease to exist ?
Can I register several events in different time on one timer, expecting them all to fire one after another ?
You can set a timer to fire off the event only once or continue to do it (Timer.AutoReset property). Yes, you can register several different event handlers on a single timer, but I don't know that there is any way of knowing what order they will fire. If that matters to you, set a single handler, and have that handler call the others. If what you are trying to do is to call a different handler, each time the timer goes off, I would suggest setting a single handler that keeps an enum indicating which function to call and incrementing it each time it gets called by the timer.
To call the same handler to "iterate" through a list of parameters, once on each interval elapsed, I would have an array or list of the parameters and the handler would just increase a counter or consume the list.
using System.Timers;
public class MyTimedDelete {
private static List<int> ListOfIds=null;
private static System.Timers.Timer myTimer=null;
public static void AddIdToQueue(int id)
{
if (ListOfIds == null)
{
ListOfIds = new List<int>();
myTimer = new System.Timers.Timer(2000);
myTimer.Elapsed += OnTimedEvent;
}
ListOfIds.Add(id);
if (ListOfIds.Count==1)
{
myTimer.Start();
}
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
deleteItem(ListOfIds[0]);
ListOfIds.RemoveAt(0);
if (ListOfIds.Count == 0) {
myTimer.Stop();
}
}
}

EventArgs has always the same value when trying to pass parameters to event handler

I want to pass parameters to the event handler of a web method. I added an auto-unsubscription logic to avoid that the event handler gets fired multiple times. The problem is that I always get the same instance of the EventArgs object in the event handling method.
ie: If I call GetInfo 3 times with 3 different values for infoVersion, the event handling function gets fired 3 times but I will always get the same instance of the variable e.
public void GetInfo(int infoVersion)
{
System.EventHandler<ServiceReference.getInfoCompletedEventArgs> handler = null;
handler = (sender, e) =>
{
client.getInfoCompleted -= handler;
client_getInfoCompleted(sender, e, infoVersion);
};
client.getInfoCompleted += handler;
client.getInfoAsync(infoVersion);
}
void client_getInfoCompleted(object sender, ServiceReference.getInfoCompletedEventArgs e, int infoVersion)
{
//do something with e.result and infoVersion
//e.result is always the same but infoVersion is correct
}
EDIT: The web method has been tested and works fine. The e.result shall change if I modify the infoVersion value.
If I use a more simple approach like below, e.result will be different each time:
public void GetInfo(int infoVersion)
{
client.getInfoCompleted += client_getInfoCompleted;
client.getInfoAsync(infoVersion);
}
void client_getInfoCompleted(object sender, ServiceReference.getInfoCompletedEventArgs e)
{
//e.result has a different value each time.
}
Haha thats a cute one. The first event that fires calls the handler for all 3 calls and removes their event registration, which makes the other ones not arrive.
To solve this, you can create a client for each call so the events won't intersect with each other.
A better solution would be using an async API that will recieve a callback for each call. If this is an automatically generated proxy class you can make it generate these kinds of methods.
Note: This requires .Net 4.5

Timer to fire an event WPF

I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer

C# - Use a delegate to run a method at the same time every hour [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Run a code in given time interval
I have a method that runs on the hour. I am currently doing this like so:
while (true)
{
string rightNow = DateTime.Now.ToString("mm");
if (rightNow == "00")
{
RunMyMethod();
}
Thread.Sleep(10000);
}
I have been reliably informed by a friend that I'm an idiot (and generally a bad person), and that I should be using events and delegates to do this instead. I get that, outside the scope of any methods I need declare a delegate with the same return type as my method, and with the same input parameters like so:
public delegate void MyMethodsDelegate();
Then, when I want to use my delegate I instantiate it in the same way I instanciate a class like so:
MyMethodsDelegate foobar = new MyMethodsDelegate(RunMyMethod);
Then I can invoke my delegate like so:
foobar.Invoke();
Ok so I have my delegate setup, how about the event? The event I want to create is 'It's x o'clock', then every time it's x o'clock this kicks off my delegate
Also, am I setting up my delegate correctly?
Thanks
You can use System.Timers.Timer class which executes a delegate asynchronously and raises the Elapsed event when given time interval is elapsed. I would strongly recommend you reading MSDN remarks part for the Timer class, see here.
System.Timers.Timer timer = new Timer(60 * 60 * 100);
Case 1: Subscribe to anonymous method
timer.Elapsed += (s, e) =>
{
// callback code here
};
Case 2: Subscribe to explicitly defined delegate
ElapsedEventHandler handler = (s, e) =>
{
// callback code here
};
timer.Elapsed += handler;
Case 3: Subscribe to the existing method
timer.Elapsed += this.OnHourElapsed;
private void OnHourElapsed(object sender, EventArgs args)
{
// callback code here
}
Then finally just start a timer
timer.Start();

C# - anonymous functions and event handlers

I have the following code:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
Notice how I register my event member (FoundStep) to local in-place anonymous function.
My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)
I hope my question was clear.
Your code has a few problems (some you and others have identified):
The anonymous delegate cannot be removed from the event as coded.
The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.
To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
Below is approach about how unsubscribe event in anonymous method:
DispatcherTimer _timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
EventHandler handler = null;
int i = 0;
_timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev)
{
i++;
if(i==10)
_timer.Tick -= handler;
});
_timer.Start();
No, it will not be removed automatically. In this sense, there's not a difference between an anonymous method and a "normal" method. If you want, you should manually unsubscribe from the event.
Actually, it'll capture other variables (e.g. res in your example) and keep them alive (prevents garbage collector from collecting them) too.
When using an anonymous delegate (or a lambda expression) to subscribe to an event does not allow you to easily unsubscribe from that event later. An event handler is never automatically unsubscribed.
If you look at your code, even though you declare and subscribe to the event in a function, the event you are subscribing to is on the class, so once subscribed it will always be subscribed even after the function exits. The other important thing to realize is that each time this function is called, it will subscribe to the event again. This is perfectly legal since events are essentially multicast delegates and allow multiple subscribers. (This may or may not be what you intend.)
In order to unsubscribe from the delegate before you exit the function, you would need to store the anonymous delegate in a delegate variable and add the delegate to the event. You should then be able to remove the delegate from the event before the function exits.
For these reasons, if you will have to unsubscribe from the event at some later point it is not recommended to use anonymous delegates. See How to: Subscribe to and Unsubscribe from Events (C# Programming Guide) (specifically the section titled "To subscribe to events by using an anonymous method").

Categories

Resources