I've created an event handler that simply returns a list of objects that I receive from a web service when the call completes.
Now I went ahead and ran the app in debug mode and found out that the first time the event is called it works perfectly, but immediately after it completes the event is being fired for a second time. I've checked and am absolutely sure I am not calling the event more than once in the receiver class.
This is my first shot at creating custom event handlers inside my applications so I am not entirely sure the implementation is 100% accurate.
Any ideas of what might be causing this? Is the way I created the event handler accurate?
This is the DataHelper class
public class DataHelper
{
public delegate void DataCalledEventHandler(object sender, List<DataItem> dateItemList);
public event DataCalledEventHandler DataCalled;
public DataHelper()
{
}
public void CallData()
{
List<DataItem> dataItems = new List<DataItem>();
//SOME CODE THAT RETURNS DATA
DataCalled(this, dataItems);
}
}
This is where I subscribed to my event:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
GetNewDataItems();
}
private void GetNewDataItems()
{
try
{
DataHelper dataHelper = new DataHelper();
dataHelper.CallData();
dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);
}
catch
{
//Handle any errors
}
}
}
void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
{
//Do something with results
//NOTE: THIS IS WHERE THE EXCEPTION OCCURS WHEN EVENT IS FIRED FOR SECOND TIME
}
Probably you added the delegate twice, is it possible?
In this case the problem is not in who calls the delegate but in who adds the delegate to the event.
Probably you did something like...
private Class1 instance1;
void callback(...)
{
}
void myfunction()
{
this.instance1.DataCalled += this.callback;
this.instance1.DataCalled += this.callback;
}
If not, try to add a breakpoint where you subscribe to the event and see if it is called twice.
As a side note, you should always check for null when calling an event, if there is no subscriber you can get a NullReferenceException.
I would also suggest you to use a variable to store the event delegate to avoid the risk of multithreading failure.
public void CallData()
{
List<DataItem> dataItems = new List<DataItem>();
var handler = this.DataCalled;
if (handler != null)
handler(this, dataItems);
}
Edit: since now I see the code, is obvious that each time you call the GetNewDataItems method you are subsribing every time to the event.
Do in such a way you subscribe only once, for example, in constructor, or store your variable somewhere or deregister the event when you finish.
This code contains also a probable memory leak: every time you add a delegate you keep alive both the instance that contains the event and the instance that contains the subscribed method, at least, until both are unreferenced.
You can try to do something like this...
void dataHelper_DataCalled(object sender, List<DataItem> dataItemsList)
{
// Deregister the event...
(sender as Class1).DataCalled -= dataHelper_DataCalled;
//Do something with results
}
In this way however you must ensure that if there is not an exception during the event registration the event will be fired or you have again memory leaks.
Instead of an event perhaps you need just a delegate. Of course you should set your delegate field to null when you want to release the delegate.
// in data helper class
private DataHelper.DataCalledEventHandler myFunctor;
public void CallData(DataHelper.DataCalledEventHandler functor)
{
this.myFunctor = functor;
//SOME CODE THAT RETURNS DATA
}
// when the call completes, asynchronously...
private void WhenTheCallCompletes()
{
var functor = this.myFunctor;
if (functor != null)
{
this.myFunctor = null;
List<DataItem> dataItems = new List<DataItem>();
functor(this, dataItems);
}
}
// in your function
... dataHelper.CallData(this.dataHelper_DataCalled); ...
The below lines on your code should be flipped. That is
These lines
dataHelper.CallData();
dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);
Should be:
dataHelper.DataCalled += new DataHelper.DataCalledEventHandler(dataHelper_DataCalled);
dataHelper.CallData();
Because you first need to attach the event handler and then call other methods on the object which can raise the event
Related
I'm writing a program that logs user idle time, however when I attempt to run the program it throws a Stack Overflow Exception.
These are my custom events
public void OnInactive(EventArgs e)
{
this.OnInactive(new EventArgs());
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
public void OnActive(EventArgs e)
{
this.OnActive(new EventArgs());
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
I've breakpointed the code to try and locate the source of the issue, which appears to lie within this.OnInactive(new EventArgs());, However I'm pretty stumped on how to resolve this issue as I'm a beginner to Custom Events and haven't been coding in C# for long.
Any and all help with this issue would be greatly appreciated!
Thanks in Advance =]
Your handler method is calling itself immediately on entry:
this.OnInactive(new EventArgs());
this leads to a sequence of calls:
OnInactive -> OnInactive -> OnInactive -> ... ->
which will continue until you run out of stack space and the StackOverflowException is thrown by the runtime.
It's not clear what you're trying to achieve with the recursive call, but you should be able to just remove it.
You have the same issue in your OnActive handler.
EDIT: In response to the comments, it seems you're trying to raise the event itself at the beginning of your method. Assuming your event declaration looks like:
public event EventHandler InActive;
then you can raise it with:
EventHandler inactiveEvent = this.InActive;
if(inactiveEvent != null)
{
inactiveEvent(this, e);
}
and similarly for your Active event.
I gues you are trying to call the base method, but in fact you are now calling OnInactive when hitting OnInactive. This behaviour is recursive and will finaly stop due StackOverflow exception.
You can call the base function with base.<function name>.
For example:
class SpecialDerived : Base
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
More info: http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx
I think what you need is a bit more understanding about events. Let me explain the same through a sample code.
Class A{
public event OnInactive;
public event OnActive;
}
when any changes occur in classA you want to update things in ClassB. So you will implement events of class A in ClassB.
this link will describe you the same in detail.
My understanding says that there is no use of events when you are triggering it from the same class and listening in the same class.
these aren't event handlers, these are the methods that are going to
be called in order to raise the active and inactive events – Reece
Cottam
You need to actually call the event.
public class ReecesWatcher
{
public event EventHandler ActiveEvent;
public event EventHandler InactiveEvent;
protected virtual void OnInactive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler inactiveEventTest = InactiveEvent;
if (inactiveEventTest != null)
{
inactiveEventTest(this, new EventArgs());
}
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
protected virtual void OnActive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler activeEventTest = ActiveEvent;
if (activeEventTest != null)
{
activeEventTest(this, new EventArgs());
}
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
// ... the rest of your class, where you call OnActive and OnInactive to
// cause the events to be fired.
}
I recommend not making your OnActive and OnInactive methods public, otherwise you're exposing too much of the implementation to the rest of your program. If you expect the class to be inherited from, then make them protected, otherwise I usually make them entirely private, since they're basically wrapper functions called by the rest of the class.
I've seen many developers when wanting to invoke an Event they assign it to a local variable named handler and invoke handler instead of invoking Event directly.
Why we are not invoking Events directly?
private void OnSomethingChanged(EventArgs e)
{
if (SomethingEvent != null)
{
SomethingEvent(this, e);
}
}
The code you've posted isn't thread-safe, basically. If the final subscriber unsubscribes in a different thread after the if check but before the invocation, you'll get a NullReferenceException.
One option is to write an extension method:
public static void NullSafeInvoke(this EventHandler handler,
object sender, EventArgs e)
{
if (handler != null)
{
handler(this, e);
}
}
You can then write:
private void OnSomethingChanged(EventArgs e)
{
SomethingEvent.NullSafeInvoke(this, e);
}
You'd probably want another overload for EventHandler<T>, too.
There is a possibility of a race condition if the event is not copied (relevant to multi-threaded applications only).
If one thread unsubscribes from the event just after the null check leaving nothing subscribed to it, you will get a NullReferenceException.
I also don't understand why. There is a simple and pretty safe method:
// when constructing of instance, to create empty subscription
public event EventHandler SomethingEvent = delegate { };
private void OnSomethingChanged(EventArgs e)
{
// and call it directly
SomethingEvent(this, e);
}
I have some C# code that updates some properties of an object. I have an event handler defined to help me respond when the update process is done. Unfortunately, I've learned that this event is getting fired multiple times. I suspect this is happening because the event handler is being set at the wrong time. Currently, it is being set like the following:
myObject.Update_Succeeded += new EventHandler(myObject_Update_Succeeded);
Due to the complexity of the code, I'm having a difficult time of tracking down where it should be set. I would like to only set the event handler it hasn't been previously set. Because of this, I want to do something like this:
ClearEventHandlers(myObject);
or
myObject.Update_Succeeded = null;
myObject.Update_Succeeded += new EventHandler(myObject_Update_Succeeded);
Is there a way to accomplish what I'm trying?
Thank you!
Yes, you can customize the add/remove accessors of your event. This article describes these accessors. But you can do something like:
class MyClass
{
private EventHandler _myEvent;
public event EventHandler MyEvent
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_myEvent = (EventHandler)Delegate.Combine(_myEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_myEvent = (EventHandler)Delegate.Remove(_myEvent, value);
}
}
public void ClearMyEvent() {
_myEvent = null;
}
...
}
You should be able to remove a handler using the subtract operator like below
myObject.Update_Succeeded -= new EventHandler(myObject_Update_Succeeded);
Or check this out for a way to remove all event handler if you are in doubt
How to remove all event handlers from a control
Proper way should be to detach the handler from each event after you no longer use it:
public class MyObjectListener
{
private readonly MyObject _object;
public class MyObjectListener(MyObject obj)
{
_object = obj;
Attach();
}
// adds event handlers
private void Attach()
{
obj.UpdateSucceeded += UpdateSuceededHandler;
obj.UpdateFailed += UpdateFailedHandler;
}
// removes event handlers
private void Detach()
{
obj.UpdateSucceeded -= UpdateSuceededHandler;
obj.UpdateFailed -= UpdateFailedHandler;
}
...
}
The only thing you need to decide is where to call the Detach method. For example, you can call it in the handler itself:
private void UpdateSuceededHandler(object sender, Data args)
{
Detach();
// do something when it succeeds
}
private void UpdateFailedHandler(object sender, Data args)
{
Detach();
// do something when it fails
}
Or, you could allow users of MyObjectListener to tell it that it no longer needs to listen to the attached object:
public void StopListening()
{
Detach();
}
An object which raises an event should not allow its listeners to modify the event invocation list. Each event listener should subscribe or unsubscribe its own event handlers only.
You better set event handler on the initialization of your object i.e. in your Constructor.
I would like to hear opinions on below code snippet. Is there anything that can be improved? Is the event handler/raiser naming following best practices? I know it is not that useful to handle and raise events in the same class but this is just a snippet.
public class MyControl
{
public MyControl()
{
this.LogWritten += this.HandleMyControlLogWritten;
}
// Event handler
void HandleMyControlLogWritten(object sender, EventArgs e)
{
}
// Event object
public event Action<object, EventArgs> LogWritten;
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
if (this.LogWritten != null)
{
this.LogWritten(this, e);
}
}
}
The main change I'd recommend would be to get a copy of the event handler:
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
var handler = this.LogWritten;
if (handler != null)
{
handler(this, e);
}
}
This is important if you're planning to (eventually) use this class in a multi-threaded scenario. As such, I find that it's a good "best practice" to get into the habit of using. The issue is that, when using in multiple threads, without creating the copy, it's possible that the only "handler" attached could unsubscribe between the null check and the invocation, which would cause a runtime error. By copying to a temporary variable (the var handler = this.LogWritten;) line, you're effectively creating a "snapshot" of the subscriber list, and then checking it for null and invoking if required.
The other change is in the event declaration itself. Instead of using Action<T1,T2>:
// Event object
public event Action<object, EventArgs> LogWritten;
I would recommend using EventHandler<TEventArgs> (if you want to use a custom EventArgs subclass) or EventHandler (for standard EventArgs). These are more "standard practice", and will be what other developers expect:
// Event object
public event EventHandler LogWritten;
I have a static class that I would like to raise an event as part of a try catch block within a static method of that class.
For example in this method I would like to raise a custom event in the catch.
public static void saveMyMessage(String message)
{
try
{
//Do Database stuff
}
catch (Exception e)
{
//Raise custom event here
}
}
Thank you.
Important: be very careful about subscribing to a static event from instances. Static-to-static is fine, but a subscription from a static event to an instance handler is a great (read: very dangerous) way to keep that instance alive forever. GC will see the link, and will not collect the instance unless you unsubscribe (or use something like a WeakReference).
The pattern for creating static events is the same as instance events, just with static:
public static event EventHandler SomeEvent;
To make life easier (re null checking), a useful trick here is to add a trivial handler:
public static event EventHandler SomeEvent = delegate {};
Then you can simply invoke it without the null-check:
SomeEvent(null, EventArgs.Empty);
Note that because delegate instances are immutable, and de-referencing is thread-safe, there is never a race condition here, and no need to lock... who-ever is subscribed when we de-reference gets invoked.
(adjust for your own event-args etc).
This trick applies equally to instance events.
Your event would also need to be static:
public class ErrorEventArgs : EventArgs
{
private Exception error;
private string message;
public ErrorEventArgs(Exception ex, string msg)
{
error = ex;
message = msg;
}
public Exception Error
{
get { return error; }
}
public string Message
{
get { return message; }
}
}
public static class Service
{
public static EventHandler<ErrorEventArgs> OnError;
public static void SaveMyMessage(String message)
{
EventHandler<ErrorEventArgs> errorEvent = OnError;
if (errorEvent != null)
{
errorEvent(null, new ErrorEventArgs(null, message));
}
}
}
And Usage:
public class Test
{
public void OnError(object sender, ErrorEventArgs args)
{
Console.WriteLine(args.Message);
}
}
Test t = new Test();
Service.OnError += t.OnError;
Service.SaveMyMessage("Test message");
Several folks have offered up code examples, just don't fire an event using code such as:
if(null != ExampleEvent)
{
ExampleEvent(/* put parameters here, for events: sender, eventArgs */);
}
as this contains a race condition between when you check the event for null and when you actually fire the event. Instead use a simple variation:
MyEvent exampleEventCopy = ExampleEvent;
if(null != exampleEventCopy)
{
exampleEventCopy(/* put parameters here, for events: sender, eventArgs */);
}
This will copy any event subscribers into the exampleEventCopy, which you can then use as a local-only version of the public event without having to worry about any race conditions (Essentially, it is possible that another thread could pre-empt you right after you have checked the public event for null and proceed to remove all subscribers from the event, causing the subsequent firing of the event to throw an exception, by using a local-only copy, you avoid the possibility of another thread removing subscribers, since there is no way they could access the local variable).
Note: VS2008, C#
Just declare an event as you normally would within the static class, but be sure to mark the event as static:
public static event EventHandler Work;
Then just subscribe to it as you normally would.
Just to add "Delegates are immutable" So, as shown in the example above the following line obtains a copy of the delegate.
EventHandler<ErrorEventArgs> errorEvent = OnError;
The way I did this is the following:
1- define a delegate (this will enable you to have customized arguments):
public delegate void CustomeEventHandler(string str);
2- define an event based on the previously defined delegate:
public static event CustomeEventHandler ReadLine;
3- create an event handler:
static void OnLineRead(string currentLine)
{
if (ReadLine != null)
ReadLine(currentLine);
}
4- raise your event using the event handler (just call it wherever you want the event to be raised).