This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...
Related
I have an application with a gui and a Rich Text Box where I output what the program is currently doing since data processing can be quite long.
I tried two approaches for that:
1 In the Backgroundworker method I can just call the following code fine:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
Whereas I cannot use Form1.Processchange(); in the helper class due to the non static context
2 Therefore I tried to create my very first eventhandler.
The Idea was that helper.UpdateConsole() would raise an event
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
to which the Backgroundworker listens and then calls Processchange from its context
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks();
Helper helper = new Helper();
helper.OnConsoleUpdate += Processchange;
task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
//MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
GlobalVar.next = false;
backgroundWorker1.ReportProgress(1);
while (GlobalVar.next == false)
{
helper.TimeBreaker(100,"ms");
}
}
Unfortunately this was was not successful. As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work.
Edit: the OnConsoleUpdate() == null as shown on the screenshot below
event = null
The helper is in another class file "helpers" which might be important for a solution.
i hope you guys can help me out.
Welcome to SO!
A few things immediately jump to mind.
First, let's get the event issue out of the way. You've got the correct approach - you need an event and method to call it, but that method should check if the event is null.
Basically, do this:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
The above makes use of ?, a null-condition operator. You can read more about it on this MSDN page.
Second thing... it's unclear what your background worker actually IS. It sounds like it's some kind of custom class you crated? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true). And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own.
Here's how you can use the standard .NET BackgroundWorker:
System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
void StartBackgroundTask()
{
worker.DoWork += worker_DoWork;
//if it's possible to display progress, use this
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
//what to do when the method finishes?
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
//start!
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
//perform any "finalization" operations, like re-enable disabled buttons
//display the result using the data in e.Result
//this code will be running in the UI thread
}
//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
public string OperationDescription { get; set; }
public int CurrentResult { get; set; }
//feel free to add more stuff here
}
void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
//display the progress using e.ProgressPercentage or e.UserState
//this code will be running in the UI thread
//UserState can be ANYTHING:
//var data = (ProgressData)e.UserState;
}
void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//this code will NOT be running in the UI thread!
//you should NOT call the UI thread from this method
int result = 1;
//perform calculations
for (var i = 1; i <= 10; i++)
{
worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
result *= i;
}
e.Result = result;
}
Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage.
There's one more worrisome thing in your code.
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks(); //<- you create a task
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}
Do note that events, unless made static, aren't global. So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this:
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above
Usually this is the stuff i would spend a few hours browsing google and stackoverflow for, however i ran into the problem of how the heck do i word this for a search engine.
I hoping there is a simple way of achieving this, as my current method feels far to "hackish"
What I need to do, if track when several sources of data have completed their loading, and only when all have completed do i load a new view (this is WPF mvvm). Now the data is loaded via a static class termed Repository each one creates a thread and ensure they only a single load operation can happen at once (to avoid multiple threads trying to load into the same collection), each of these classes fires an event called LoadingCompleted when they have finished loading.
I have a single location that loads a large portion of the data (for the first time, there are other locations where the data is reloaded however) what i planned was to hook into each repositories OnLoaded event, and keep track of which have already returned, and when one is returned, mark it as loaded and check to see if any remain. If none remain load the new view, else do nothing.
Something like this:
ShipmentRepository.LoadingComplete += ShipmentRepository_LoadingComplete;
ContainerRepository.LoadingComplete += ContainerRepository_LoadingComplete;
void ContainerRepository_LoadingComplete(object sender, EventArgs e)
{
_containerLoaded = true;
CheckLoaded();
}
void ShipmentRepository_LoadingComplete(object sender, EventArgs e)
{
_shipmentsLoaded = true;
CheckLoaded();
}
private void CheckLoaded()
{
if(_shipmentsLoaded && _containersLoaded && _packagesLoaded)
{
LoadView();
}
}
However as i mentioned this feels clumbsy and hackish, I was hoping there was a cleaner method of doing this.
You can achieve this with Reactive Extensions and using Observable.FromEventPattern in conjunction with the Observable.Zip method. You should be able to do something like:
var shipmentRepositoryLoadingComplete = Observable.FromEventPattern<EventHandler,EventArgs>(h => ShipmentRepository.LoadingComplete += h, h => ShipmentRepository.LoadingComplete -= h);
var containerRepositoryLoadingComplete = Observable.FromEventPattern<EventHandler, EventArgs>(h => ContainerRepository.LoadingComplete += h, h => ContainerRepository.LoadingComplete -= h);
Then you subscibe to the observalbes like this:
var subscription = Observable.Zip(shipmentRepositoryLoadingComplete, containerRepositoryLoadingComplete)
.Subscribe(l => LoadView()));
The subscirption needs to stay alive, so you can save this as a private variable. When both complete events are invoked, the LoadView method should be called. Here is a working console example I used to test this method.
using System;
using System.Reactive.Linq;
namespace RxEventCombine
{
class Program
{
public event EventHandler event1;
public event EventHandler event2;
public event EventHandler event3;
public Program()
{
event1 += Event1Completed;
event2 += Event2Completed;
event3 += Event3Completed;
}
public void Event1Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 1 completed");
}
public void Event2Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 2 completed");
}
public void Event3Completed(object sender, EventArgs args)
{
Console.WriteLine("Event 3 completed");
}
static void Main(string[] args)
{
var program = new Program();
var event1Observable = Observable.FromEventPattern<EventHandler,EventArgs>(h => program.event1 += h, h => program.event1 -= h);
var event2Observable = Observable.FromEventPattern<EventHandler, EventArgs>(h => program.event2 += h, h => program.event2 -= h);
var event3Observable = Observable.FromEventPattern<EventHandler, EventArgs>(h => program.event3 += h, h => program.event3 -= h);
using (var subscription = Observable.Zip(event1Observable, event2Observable, event3Observable)
.Subscribe(l => Console.WriteLine("All events completed")))
{
Console.WriteLine("Invoke event 1");
program.event1.Invoke(null, null);
Console.WriteLine("Invoke event 2");
program.event2.Invoke(null, null);
Console.WriteLine("Invoke event 3");
program.event3.Invoke(null, null);
}
Console.ReadKey();
}
}
}
Output
Invoke event 1
Event 1 completed
Invoke event 2
Event 2 completed
Invoke event 3
Event 3 completed
All events completed
Another way to do this: Add a property LoadingCompleted. For every instance you start a thread return that object to a list. On every loadcompleted set the property to true and in the place you catch the load completed loop through the list (myList.Any(x=>LoadingCompleted == false)) to figure out if everything is completed.
Not the most correct way to do it. But reading your scenario this might do the job.
If you are loading the shipments, containers and packages as asynchronous task then you have several options. As others suggested you can use WhenAll or Join() to wait for all threads to finish before proceeding. However, if your threads have to stay alive and the threads don't stop when they have finished loading, you can use the System.Threading.CountdownEvent as following:
Edit
Added how I would set up the threads and handle the events. Also moved the example from the static Program to an instance, more closely resembeling your situation. Again, if you do not need to do anything in the threads after they have loaded the data, just skip the CountdownEvent altogether and wait for all threads to finish. Much simpler, does not need events and can be achieved using Join() or in this case Task.WaitAll().
class Program
{
static void Main(string[] args)
{
var myWpfObject = new MyWpfObject();
}
}
public class MyWpfObject
{
CountdownEvent countdownEvent;
public MyWpfObject()
{
ShipmentRepository ShipmentRepository = new ShipmentRepository();
ContainerRepository ContainerRepository = new ContainerRepository();
PackageRepository PackageRepository = new PackageRepository();
ShipmentRepository.LoadingComplete += Repository_LoadingComplete;
ContainerRepository.LoadingComplete += Repository_LoadingComplete;
PackageRepository.LoadingComplete += Repository_LoadingComplete;
Task[] loadingTasks = new Task[] {
new Task(ShipmentRepository.Load),
new Task(ContainerRepository.Load),
new Task(PackageRepository.Load)
};
countdownEvent = new CountdownEvent(loadingTasks.Length);
foreach (var task in loadingTasks)
task.Start();
// Wait till everything is loaded.
countdownEvent.Wait();
Console.WriteLine("Everything Loaded");
//Wait till aditional tasks are completed.
Task.WaitAll(loadingTasks);
Console.WriteLine("Everything Completed");
Console.ReadKey();
}
public void Repository_LoadingComplete(object sender, EventArgs e)
{
countdownEvent.Signal();
}
}
And a mock Repository class:
public class ShipmentRepository
{
public ShipmentRepository()
{
}
public void Load()
{
//Simulate work
Thread.Sleep(1000);
if (LoadingComplete != null)
LoadingComplete(this, new EventArgs());
Console.WriteLine("Finished loading shipments");
DoAditionalWork();
}
private void DoAditionalWork()
{
//Do aditional work after everything is loaded
Thread.Sleep(5000);
Console.WriteLine("Finished aditional shipment work");
}
public event EventHandler LoadingComplete;
}
At the moment I am in the process of building a custom button handler (I needed to integrate the kinect into the button system which also used a mouse) then I got to a horrible thing called Event Handling.. at least an hour yelling at my pc :P. I was wondering, before I go and spend a while changing my system to allow for my new want, which is to have multiple events per handler, I was wondering, is the way I'm going to try work (I would just try, but I'm getting off for the night, so my hope is that I can save some time when I boot the computer up tomorrow and not attempt if my system isn't designed for it)
Also, ive seen a getInvoc list or somthing like that before when I was coding.. Would I add multiple delegates onto it then get that list and itterate over it?
On previous examples I had seen where people used:
public event EventHandler myEventHandler;
I had to use:
private Dictionary<BtnEvent, Delegate> m_events;
and then they did the following to add a handler (their way, not mine):
myObj.myEventHandler += delegate(object sender, EventArgs ea)
{
//do stuff on event
};
first.. If they ran this twice, once with funcA and second with funcb would it run both? or just one?
second, if I applied that logic of += to a Delegate would it work? (I had to use Delegate as I was storing the handlers inside of a dictionary, this allowed for logical access to handlers through use of an enum)
(my code)
private Dictionary<BtnEvent, Delegate> m_events;
//....
m_events = new Dictionary<BtnEvent, Delegate>(6);
m_events.Add(BtnEvent.CLICK_ENTER, null);
m_events.Add(BtnEvent.CLICK_LEAVE, null);
m_events.Add(BtnEvent.CLICK_STAY, null);
m_events.Add(BtnEvent.HOVER_ENTER, null);
m_events.Add(BtnEvent.HOVER_LEAVE, null);
m_events.Add(BtnEvent.HOVER_STAY, null);
//....
public bool addHandle(BtnEvent stateToGet, Delegate function)
{
bool success = false;
if(m_events.ContainsKey(stateToGet))
{
m_events[stateToGet] = function;
}
return(success);
}
// CHANGE ABOVE TO:
public bool addHandle(BtnEvent stateToGet, Delegate function)
{
bool success = false;
if(m_events.ContainsKey(stateToGet))
{
m_events[stateToGet] += function;
}
return(success);
}
Will changing m_events[stateToGet] = function; to m_events[stateToGet] += function; allow me to have multiple event handles (functions I passed to addHandle) be called through the following code?
private void ExecuteEvent(BtnEvent currEvent)
{
if(m_events.ContainsKey(currEvent))
{
if(m_events[currEvent] != null)
{
m_events[currEvent].DynamicInvoke(null);
}
}
}
Please see below code which answers your first question:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
funcA();
funcB();
}
private void funcA()
{
button1.Click += new EventHandler(button1_Click);
}
private void funcB()
{
button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("I am in event handler");
}
}
On clicking the Button, "I am in event handler" message is shown twice which means += operator works in similar way with delegates as it works with integers or strings. It simply adds the function handler to the queue and upon execution of events, calls all the function pointers in queue.
Regarding your second question, I think you wont achieve the expected behavior by changing = to +=. What I understand from your statement is that, you wish to execute multiple events handlers like CLICK_ENTER, CLICK_LEAVE on calling ExecuteEvent() function. However, since you are storing event handlers and their delegates in a Dictionary, changing = to += will only work in the same way as illustrated in above code.
In a similar question:
What is this pattern called? Soft Lock?
I was asking about the name of the pattern for the code listing below.
public class MyClass
{
public event EventHandler MyEvent;
private bool IsHandlingEvent = false;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
if (IsHandlingEvent) { return; }
IsHandlingEvent = true;
{
// Code goes here that handles the event, possibly invoking 'MyEvent' again.
// IsHandlingEvent flag is used to avoid redundant processing. What is this
// technique, or pattern called.
// ...
}
IsHandlingEvent = false;
}
}
It seems that most of the conversation was centered around why we should an should not do this, so I think that this question provides a better forum to tackle the problem and address all of the issues. What is the better / proper way to handle this?
There are series of problems with that pattern. If you want to invoke the handler only once, you would do something like this:
protected static object _lockObj = new object();
protected static bool _isHandled = false;
void MyClass_MyEvent(object sender, EventArgs e)
{
if(_isHandled)
return;
lock(_lockObj)
{
if(_isHandled)
return;
_isHandled = true;
MyOtherPossiblyRecursiveMethod(); // Actually does all your work
_isHandled = false;
}
}
void MyOtherPossiblyRecursiveMethod()
{
}
This way, only one thread should be able to access the actual work method.
I will use something like:
using( var sl = new SoftLock() )
{
sl.Execute(()=>{....});
}
the execute will raise the internal boolean to prevent re-entering. In the dispose that flag would be resetted. Execute will call the lambda just if the flag is false. This is to ensure flag go to false even if exception happens ( causing handler never executed ) and maybe is a little better to see. Of course this is not thread safe, as the original code, but this because we are talking about preventing double execution from the same thread.
The original code is a sufficient (and very lightweight) way to prevent recursion in a single-threaded app. So if during your event handling function you could get into code that might be firing the event again you will not enter infinite recursion.
But the code is not sufficient to prevent access from multiple threads, due to the potential for race conditions. If you need to ensure only one thread gets to run this event, then you should use a stronger locking mechanism, like a Mutex or Semaphore.
The following works in single- and multi-threaded scenarios and is exception-safe... also if need be it can be modified to allow for a certain level of reentrancy (for example 3 levels)...
public class MyClass
{
public event EventHandler MyEvent;
private int IsHandlingEvent = 0;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
// this allows for nesting if needed by comparing for example < 3 or similar
if (Interlocked.Increment (ref IsHandlingEvent) == 1 )
{
try {
}
finally {};
}
Interlocked.Decrement (ref IsHandlingEvent);
}
}
I need to be able to delay the event handlers for some controls (like a button) to be fired for example after 1 sec of the actual event (click event for example) .. is this possible by the .net framework ?
I use a timer and call my code from the timer's tick event as below but I am not sure if this is the best approach !
void onButtonClick( ..)
{
timer1.Enabled = true;
}
void onTimerTick( ..)
{
timer.Enabled = false;
CallMyCodeNow();
}
Perhaps you could make a method that creates the timer?
void onButtonClick(object sender, EventArgs e)
{
Delay(1000, (o,a) => MessageBox.Show("Test"));
}
static void Delay(int ms, EventHandler action)
{
var tmp = new Timer {Interval = ms};
tmp.Tick += new EventHandler((o, e) => tmp.Enabled = false);
tmp.Tick += action;
tmp.Enabled = true;
}
Before coming to your question, just having read the summary bit from the main questions page, a timer was exactly what I was going to suggest.
This looks pretty clean to me. It means you can easily "cancel" the delayed event if you need to, by disabling the timer again, for example. It also does everything within the UI thread (but without reentrancy), which makes life a bit simpler than other alternatives might be.
If you're only doing this for one control, the timer approach will work fine. A more robust approach supporting multiple controls and types of events looks something like this:
class Event
{
public DateTime StartTime { get; set; }
public Action Method { get; set; }
public Event(Action method)
{
Method = method;
StartTime = DateTime.Now + TimeSpan.FromSeconds(1);
}
}
Maintain a Queue<Event> in your form and have UI events that need to be delayed add them to the queue, e.g.:
void onButtonClick( ..)
{
EventQueue.Enqueue(new Event(MethodToCall));
}
Make your timer tick 10 times a second or so, and have its Tick event handler look like this:
void onTimerTick()
{
if (EventQueue.Any() && EventQueue.First().StartTime >= DateTime.Now)
{
Event e = EventQueue.Dequeue();
e.Method;
}
}
My solution uses System.Threading.Timer:
public static class ExecuteWithDelay
{
class TimerState
{
public Timer Timer;
}
public static Timer Do(Action action, int dueTime)
{
var state = new TimerState();
state.Timer = new Timer(o =>
{
action();
lock (o) // The locking should prevent the timer callback from trying to free the timer prior to the Timer field having been set.
{
((TimerState)o).Timer.Dispose();
}
}, state, dueTime, -1);
return state.Timer;
}
}
For those limited to .NET 2.0, here is another take on Bengt's helpful solution:
/// <summary>
/// Executes the specified method in a delayed context by utilizing
/// a temporary timer.
/// </summary>
/// <param name="millisecondsToDelay">The milliseconds to delay.</param>
/// <param name="methodToExecute">The method to execute.</param>
public static void DelayedExecute(int millisecondsToDelay, MethodInvoker methodToExecute)
{
Timer timer = new Timer();
timer.Interval = millisecondsToDelay;
timer.Tick += delegate
{
// This will be executed on a single (UI) thread, so lock is not necessary
// but multiple ticks may have been queued, so check for enabled.
if (timer.Enabled)
{
timer.Stop();
methodToExecute.Invoke();
timer.Dispose();
}
};
timer.Start();
}
Using Reactive Extensions:
First, install the nuget package
PM> Install-Package Rx-Main
Code:
private void CallMyCodeNow()
{
label1.Text = "reactivated!";
}
private void Form1_Load(object sender, EventArgs e)
{
var o = Observable.FromEventPattern<EventHandler, EventArgs>(
handler => button1.Click += handler
, handler => button1.Click -= handler
)
.Delay(TimeSpan.FromSeconds(5))
.ObserveOn(SynchronizationContext.Current) // ensure event fires on UI thread
.Subscribe(
ev => CallMyCodeNow()
, ex => MessageBox.Show(ex.Message)
);
}
If you're looking for a more fancy solution, you may want to take a look at my Reactive LINQ project. The link doesn't show how to solve the particular problem you're having, but it should be possible to solve in quite an elegant style using the technique described there (in the whole 4-article series).
You can use:
Thread.Sleep(1000);
That will pause the current Thread for one second. So I would do that...
Best Regards!