I have event handlers for intercepting call logs on windows mobile. The problem is more specific to event handlers in C# rather than windows mobile. I am able to attach and detach event handlers for the first time. The proble is: I am not able to attach event handler after its detached at least once. Why are the event handlers not invoked after its detached and again attached?
Below is my code:
private static SystemState stateIncoming = null;
private static SystemState stateOutgoing = null;
private static SystemState stateTalking = null;
public static void StartCallLogInterception()
{
if (stateIncoming == null && stateOutgoing == null && stateTalking == null)
{
stateIncoming = new SystemState(SystemProperty.PhoneIncomingCall);
stateIncoming.Changed += new ChangeEventHandler(stateIncoming_Changed);
stateOutgoing = new SystemState(SystemProperty.PhoneCallCalling);
stateOutgoing.Changed += new ChangeEventHandler(stateOutgoing_Changed);
stateTalking = new SystemState(SystemProperty.PhoneCallTalking);
stateTalking.Changed += new ChangeEventHandler(stateTalking_Changed);
}
}
public static void EndCallLogInterception()
{
if (stateIncoming != null && stateOutgoing != null && stateTalking != null)
{
stateIncoming.Changed -= new ChangeEventHandler(stateIncoming_Changed);
stateIncoming = null;
stateOutgoing.Changed -= new ChangeEventHandler(stateOutgoing_Changed);
stateOutgoing = null;
stateTalking.Changed -= new ChangeEventHandler(stateTalking_Changed);
stateTalking = null;
}
}
EDIT: I updated code to include class level variable. Also, below answers conflict with each other. If I am disposing object, I must re-create the object when I need to attach event handler. Does this make sense?
EDIT 2: The problem is not with objects or event handling code. I am using LargeIntervalTimer from OpenNETCF. Whenever I am running timer using LargeIntervalTimer, the event handler is not attached properly. Without LargeIntervalTimer, everything is working fine.
Well, it's not really clear from just the code you've given, but I wonder whether it's because you're never disposing of the SystemState objects you're creating. If you change your code to dispose of them properly when you unsubscribe, that may help.
Alternatively, don't bother keeping on creating new objects - just create the three objects up-front, and then subscribe/unsubscribe as appropriate.
You don't need the
stateTalking.Changed -= new ChangeEventHandler(stateTalking_Changed);
code. First, you are not removing the same thing you put in, you are removing a new instance og the ChangeVenetHandler. Second, all event handlers are removed when you run
stateTalking = null;
because of the Garage Collection.
As Jon Skeet said, you never run the code
stateTalking.Dispose();
before you remove it.
Check your if statements. Place a break point and make sure that you even enter the condition that wires-up the handlers. I suspect that you are not reaching the code in subsequent calls, likely because one of the objects is not null.
Related
In my .NET application I am subscribing to events from another class. The subscription is conditional. I am subscribing to events when the control is visible and de-subscribing it when it become invisible. However, in some conditions I do not want to de-subscribe the event even if the control is not visible as I want the result of an operation which is happening on a background thread.
Is there a way through which I can determine if a class has already subscribed to that event?
I know we can do it in the class which will raise that event by checking the event for null, but how do I do it in a class which will subscribe to that event?
The event keyword was explicitly invented to prevent you from doing what you want to do. It restricts access to the underlying delegate object so nobody can directly mess with the events handler subscriptions that it stores. Events are accessors for a delegate, just like a property is an accessor for a field. A property only permits get and set, an event only permits add and remove.
This keeps your code safe, other code can only remove an event handler if it knows the event handler method and the target object. The C# language puts an extra layer of security in place by not allowing you to name the target object.
And WinForms puts an extra layer of security in place so it becomes difficult even if you use Reflection. It stores delegate instances in an EventHandlerList with a secret "cookie" as the key, you'd have to know the cookie to dig the object out of the list.
Well, don't go there. It is trivial to solve your problem with a bit of code on your end:
private bool mSubscribed;
private void Subscribe(bool enabled)
{
if (!enabled) textBox1.VisibleChanged -= textBox1_VisibleChanged;
else if (!mSubscribed) textBox1.VisibleChanged += textBox1_VisibleChanged;
mSubscribed = enabled;
}
Assuming that you have no access to the innards of the class declaring the event, you have no way to do it directly. Events only expose operators += and -=, nothing else. You will need a flag or some other mechanism in your subscribing class to know whether you are already subscribed or not.
/// <summary>
/// Determine if a control has the event visible subscribed to
/// </summary>
/// <param name="controlObject">The control to look for the VisibleChanged event</param>
/// <returns>True if the control is subscribed to a VisibleChanged event, False otherwise</returns>
private bool IsSubscribed(Control controlObject)
{
FieldInfo event_visible_field_info = typeof(Control).GetField("EventVisible",
BindingFlags.Static | BindingFlags.NonPublic);
object object_value = event_visible_field_info.GetValue(controlObject);
PropertyInfo events_property_info = controlObject.GetType().GetProperty("Events",
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList event_list = (EventHandlerList)events_property_info.GetValue(controlObject, null);
return (event_list[object_value] != null);
}
Simply check whether the control is visible or not whenever the event handler is triggered.
Can you put the decision making logic into the method that fires the event? Assuming you're using Winforms it'd look something like this:
if (MyEvent != null && isCriteriaFulfilled)
{
MyEvent();
}
Where isCriteriaFulfilled is determined by your visible/invisible logic.
// UPDATES /////
Further to your 1st comment would it not make sense to alter the behaviour inside your event handler depending on the value of this.Visible?
a.Delegate += new Delegate(method1);
...
private void method1()
{
if (this.Visible)
// Do Stuff
}
Or if you really have to go with subscribing and unsubscribing:
private Delegate _method1 = null;
...
if(this.visible)
{
if (_method1 == null)
_method1 = new Delegate(method1);
a.Delegate += _method1;
}
else if (_method1 != null)
{
a.Delegate -= _method1;
}
using System;
//...
public event EventHandler Event;
public bool IsSubscribed(EventHandler Delegate)
{
if (Event == null)
{
return false;
}
var InvocationList = Event.GetInvocationList();
foreach (var Entry in InvocationList)
{
if (Entry.Equals(Delegate))
{
return true;
}
}
return false;
}
After 12 years it is here, works for me.
Can't you just remember whether you already subscribed? That approach worked fine for me so far. Even if you have a lot of events or objects, you may still want to just remember that (in a dictionary, for example).
On the other hand, visibility change was, at least for me, not a good point to subscribe/unsubscribe. I typically rather go with construction / Disposed, which are more clear than each time visibility changes.
I'm just expanding on Hans' answer. I'm just trying to ensure that I'm not installing my handler more than once, and not removing it when I still need it. This doesn't protect from a malicious or malfeasant caller unsubscribing repeatedly, for that you'd need to track the callers, and that would just open you up to having repeated subscriptions overrun the tracking mechanism.
// Tracks how many times the ReflectionOnlyResolveHandler has been requested.
private static int _subscribers = 0;
/// <summary>
/// Register or unregister the ReflectionOnlyResolveHandler.
/// </summary>
/// <param name="enable"></param>
public static void SubscribeReflectionOnlyResolve(bool enable)
{
lock(_lock)
{
if (_subscribers > 0 && !enable) _subscribers -= 1;
else if (enable) _subscribers += 1;
if (enable && _subscribers == 1)
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ReflectionHelper.ReflectionOnlyResolveHandler;
else if (_subscribers == 0)
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= ReflectionHelper.ReflectionOnlyResolveHandler;
}
}
Can any body tell me what is the reason behind SQL dependeny OnChange event calls multiple times after page refresh. What could be the possible reason behind this? Before page refresh it is called only one time per change in the database.
Problem: When I refresh page each time a new SQL Dependency variable was created and also a new Change_Event_Handler associated with that new dependency variable, and when SQL dependency is called then it has to unsubscribe from all of the existing change events which made multiple calls to my function.
Solution: Define these both variable as static in class:
internal static SqlCommand command = null;
internal static SqlDependency dependency = null;
Then use the function like this, and in application start first stop the Dependency and then start again and then do other stuff like this.
Check if dependency is started already then don't create new dependency connection and similarly new ChangeEvent,
using (EmailController.command = new SqlCommand(SQL.emailmessagesbyaccount_sql(), conn.getDbConnection()))
{
defaultemailid = emailid;
EmailController.command.Parameters.Add(new SqlParameter("#emailaccountid", emailid));
EmailController.command.Notification = null;
if (EmailController.dependency == null)
{
EmailController.dependency = new SqlDependency(EmailController.command);
EmailController.dependency.OnChange += new OnChangeEventHandler(emailMessages_OnChange);
}
var reader = EmailController.command.ExecuteReader();
}
and finally you have to implement the onchange_event like this:
private void emailMessages_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
//if not null then unsubscribe the calling event
if (EmailController.dependency != null)
{
EmailController.dependency.OnChange -= emailMessages_OnChange;
}
//do my email updates
NotificationHub.EmailUpdateRecords();
// here again subscribe for the new event call re initialize the
// exising dependecy variable the one which we defined as static
SingletonDbConnect conn = SingletonDbConnect.getDbInstance();
using (EmailController.command = new SqlCommand(SQL.emailmessagesbyaccount_sql(), conn.getDbConnection()))
{
EmailController.command.Parameters.Add(new SqlParameter("#emailaccountid", defaultemailid));
EmailController.command.Notification = null;
EmailController.dependency = new SqlDependency(EmailController.command);
EmailController.dependency.OnChange += new OnChangeEventHandler(emailMessages_OnChange);
var reader = EmailController.command.ExecuteReader();
}
}
}
Actually this was my code logic but hope you will get pretty much good idea from this implementation how to handle this kind of issue which made me stumbling my head for a week.
I was having the same problem and #usman's answer helped me a lot. I change the logic of dependency_OnChange method a little bit.
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (dependency != null)
{
dependency.OnChange -= dependency_OnChange;
dependency = null;
}
if (e.Type == SqlNotificationType.Change)
{
MessagesHub.SendMessages();
}
}
I set the dependency to null if it is not null. If we don't set it to null it fires, on every page refresh and if the page is opened multiple times or opened from multiple browsers. As #usman did define the dependency as internal static and set dependency to null in the onChange method. This made my day. Hope it helps another who are facing the same problem.
Here is the situation:
public async void Test()
{
List<string> fileTypeFilter = new List<string>();
fileTypeFilter.Add(".jpg");
fileTypeFilter.Add(".png");
var folder = KnownFolders.PicturesLibrary;
var queryOptions = new QueryOptions(CommonFileQuery.OrderByName, fileTypeFilter);
var queryResults = folder.CreateFileQueryWithOptions(queryOptions);
//queryResults.ContentsChanged += null;
queryResults.ContentsChanged += QueryResults_ContentsChanged;
}
I call Test many times, so when some changes happened in that folder, QueryResults_ContentsChanged fires for manytimes, but I just want only once. I tried "+= null", but it does not work, so I have no idea how to remove all event handlers from the local variable queryResults.
I don't see any use case that requires calling your Test method many times, I suggest verify/validate your design.
What I understood from your question is, you want to check whether QueryResults_ContentsChanged is attached to any other event or not, it is not possible (unless you've your own logic).
In general, an event can be unsubscribed as below.
queryResults.ContentsChanged -= QueryResults_ContentsChanged;
Hope this helps.
You can use -= operator to Unsubscribe event.
queryResults.ContentsChanged -= QueryResults_ContentsChanged;
See MSDN for more detail that how to Subscribe and Unsubscribe events
Consider the "application" where an object (Thrower) is throwing a ball to another object (Receiver). The event (BallIsThrowed) happens when the ball is thrown.
Here are the 2 classes :
then the entry point :
And finally the methods pointed by the delegate when events are fired :
This is working well.
Now I want to comment this line :
because I want to say that the ball was not thrown.
The result is a null Exception :
This is normal because at this point BallIsThrowed is null
To solve this, I initilise my event :
But then my problem is that my code is never taking the event when I decomment "receiver.Register(thrower)"
My questions are :
How can I have the 2 method EventMethod fired ?
The best practice way to fire an event looks like this:
EventHandler ballIsThrowed = BallIsThrowed;
if (ballIsThrowed != null)
{
ballIsThrowed(this, EventArgs.Empty);
}
The reason for the temporary variable is to prevent race conditions between the null check and the execution.
Bear with me: you are setting an event handler to BallIsThrowed, then you use IthrowTheBall() to actually trigger the event, with this code:
BallIsThrowed(this, EventArgs.Empty);
When you try to call an event handler, in this case the BallIsThrowed, it must exists or it will throw a NullReferenceException. So, in order for this to work, it must exists an event handler BallIsThrowed. It actually does, until you comment this line:
//BallIsThrowed += new EventHandler(method.EventMethod2);
So basically you need to verify if the EventHandler exists before firing it:
if (BallIsThrowed != null)
BallIsThrowed(this, EventArgs.Empty);
Another (more elegant, if you ask me) way of doing this is:
(BallIsThrowed??delegate{})(this, EventArgs.Empty);
Compact, thread safe...
Two things that need to be corrected:
In your Event Invoker, check EventHandler != null because you dont know if anyone registered to your handler.
var ballThrown = BallIsThrowed;
if (ballThrown != null)
{
ballThrown(this, EventArgs.Empty);
}
For general knowledge, In order to register more then one delegate to your
EventHandler, dont register it via the = operator, but via the
+= operator, meaning you want to append a new delegate:
public void IThrowTheBall()
{
// Do stuff
// You dont have to register this delegate, you can append it to the current
// delegates already registered
BallIsThrowed += method.EventMethod1;
}
I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.