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
Related
I have this code:
private void loadGENIOFileToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog dlgFile = new OpenFileDialog();
dlgFile.InitialDirectory = Properties.Settings.Default.PreviousPath;
dlgFile.Title = "Select GENIO file";
dlgFile.Filter = "GENIO files (*.txt)|*.txt";
dlgFile.FilterIndex = 0;
dlgFile.Multiselect = false;
if (dlgFile.ShowDialog() == DialogResult.OK)
{
Properties.Settings.Default.PreviousPath = Path.GetDirectoryName(dlgFile.FileName);
DeleteView();
m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
{
mruMenu.AddFile(dlgFile.FileName);
m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
CreateView();
};
m_oThreadServices.SetGenioFilePath(dlgFile.FileName);
m_oThreadServices.start();
}
}
But I am also trying to implement a MRU handler:
private void OnMruFile(int number, String filename)
{
if (File.Exists(filename))
{
Properties.Settings.Default.PreviousPath = Path.GetDirectoryName(filename);
DeleteView();
m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
{
mruMenu.SetFirstFile(number);
m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
CreateView();
};
m_oThreadServices.SetGenioFilePath(filename);
m_oThreadServices.start();
}
else
mruMenu.RemoveFile(number);
}
}
My m_oThreadServices.OnLoadingCompleted line of code seems to require that I use += and as a result, if I first load a file, it adds the first event handler. If I then go to use the MRU list to load a different file it ends up running two OnLoadingCompleted handlers.
I tried m_oThreadServices.OnLoadingCompleted = but it will not allow it. So what is the right way for me to intercept the event handler and not end up calling both sets of code? Am I going about it wrong?
Thank you.
You should make sure your event handlers are unsubscribed from the event source once the event is raised.
In order to do that, you have to modify a bit the anonymous handlers. For instance, this snippet:
m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
{
mruMenu.AddFile(dlgFile.FileName);
m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
CreateView();
};
should be like this:
EventHandler onLoadingCompleted = null;
onLoadingCompleted = (_sender, _e) =>
{
m_oThreadServices.OnLoadingCompleted -= onLoadingCompleted;
mruMenu.AddFile(dlgFile.FileName);
m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
CreateView();
};
m_oThreadServices.OnLoadingCompleted += onLoadingCompleted;
Same for the other.
The line
EventHandler onLoadingCompleted = null;
is needed to avoid using uninitialized variable compiler error here
m_oThreadServices.OnLoadingCompleted -= onLoadingCompleted;
You can remove a handler if it's a named function:
private void OnLoadingComplete_AddFile(_sender, _e)
{
mruMenu.AddFile(dlgFile.FileName);
m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
CreateView();
}
...
m_oThreadServices.OnLoadingCompleted += OnLoadingComplete_AddFile;
...
m_oThreadServices.OnLoadingCompleted -= OnLoadingComplete_AddFile;
Removing a handler that hasn't been added (or has already been removed) is a no-op, so you can just remove the "other" handler before you add one: this will ensure there is at most one handler.
So basically += is syntactic sugar for calling Combine on your event. Delegates are stored in an Invocation List, and the default behavior when an event is fired is for each delegate in the invocation list to get called in the order they were added. This is why you cannot simply set OnLoadingCompleted to one delegate with an = sign - an event stores a list of delegates, not one.
You could remove a delegate with -= (syntactic sugar for calling Remove). Perhaps you want to formally declare the previous delegate somewhere rather than passing it as a lambda. This would let you remove it when you are done with it.
There is no straightforward way of removing anonymous or unknown events from a handler. However, you can take a look at this forum posting on MSDN: https://social.msdn.microsoft.com/Forums/vstudio/en-US/45071852-3a61-4181-9a25-068a8698b8b6/how-do-i-determine-if-an-event-has-a-handler-already?forum=netfxbcl
There is some code and discussion about using reflection to remove delegates from your event handler.
It might be better though to understand exactly what you are wanting to accomplish. Perhaps there is a better way to get the end-result that you are looking for rather than rewire events.
It isn't usually good practice to remove established event code to change the behavior of the code you want to implement. It can lead to unintended consequences, and erratic behavior. If event code is defined, it is almost always best to keep it in place and design your application around it.
On the other hand, if this is code that is added by you, or in your code-base, you can remove it, if you have done the proper research to validate its removal and not cause the application to break elsewhere. The best way to do that would be to have the event code in a named function:
public void MyEventCode(object sender, EventArgs args)
{
// Do event stuff..
}
Then you can remove the event by name:
control.DoMyEvent -= MyEventCode;
I am attempting to subscribe two events to an object. But the object is not instantiated before I try to add the events. Is there a way I can subscribe these two events and instantiate afterwards? I already have the delegates, event, event args and event handler working.
Sample Code:
Ares a;
public B()
{
a.up += new upEventHandler(doUp);
a.down += new downEventHandler(doDown);
a = new Ares();
}
I am attempting to subscribe two events to an object. But the object is not instantiated before I try to add the events. Is there a way I can subscribe these two events and instantiate afterwards?
No, absolutely not. It's exactly like trying to set properties on an object before the object exists. Try to think about how that would work - and then realize that subscribed event handlers are part of the state of an object just like properties are.
Obviously you could store the event handlers somewhere else and subscribe them later on, but as stated, the answer is simply no. It doesn't make any sense at a conceptual level, or a practical one.
It's not possible. You must instantiate the object first.
The closest thing you could do to what you're describing would be to make the events static.
class Ares {
public static event upEventHandler up;
public static event downEventHandler down;
// ...
}
And then modify B() to be:
public B() {
Ares.up += new upEventHandler(doUp);
Ares.down += new downEventHandler(doDown);
a = new Ares();
}
I assume that the events are fired in the constructor and you want to capture that.
Try refactoring the event firing code out of the constructor into a separate Initialize() method, so you would then have the following:
Ares a;
public B()
{
a = new Ares();
a.up += new upEventHandler(doUp);
a.down += new downEventHandler(doDown);
a.Initialize(); //do all init of the ares object here, not in constructor
}
Consider the situation in which you want to subscribe to an event for one and only one notification. Once the first notification lands, you unsubscribe from all future events. Would the following pattern present any memory issues? It works, but I wasn't sure if the self-referencing closure could keeps things around in memory longer than desired.
public class Entity
{
public event EventHandler NotifyEvent;
}
// And then, elsewhere, for a listen-once handler, we might do this:
Entity entity = new Entity();
Action<object, EventArgs> listener = null;
listener = (sender, args) =>
{
// do something interesting
// unsubscribe, so we only get 1 event notification
entity.NotifyEvent -= new EventHandler(listener);
};
entity.NotifyEvent += new EventHandler(listener);
Note that you have to declare 'listener' and assign a value (null). Otherwise the compiler complains about 'Use of unassigned local variable listener'
There is nothing wrong with this pattern. It's the very same pattern I and many others use for assigning and removing a lambda expression to an event handler.
While I think the general pattern is fine, I wouldn't go through Action<object, EventArgs>. I'd use:
EventHandler listener = null;
listener = (sender, args) =>
{
// do something interesting
// unsubscribe, so we only get 1 event notification
entity.NotifyEvent -= listener;
};
entity.NotifyEvent += listener;
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.
Can I test the assertion that an event was fired? Something like this:
[TestMethod]
public void EventFiresWhenChangingProperty()
{
var sut = new SystemUnderTest();
var eventRegister = new EventRegister(sut.PropertyChanged);
sut.AnyProperty = "new value";
Assert.EventWasFired(eventRegister);
}
Of course I could create an event handler, that puts some record into the test context or in an instance variable that is only read by this specific test but this seems a little bit too much plumbing. I am looking for something like the code above.
I usually hook up an anonymous method as an event listener, and set a testable value in it, like so:
var sut = new SystemUnderTest();
bool eventWasRaised = false;
sut.PropertyChanged += (s, e) => eventWasRaised = true;
sut.AnyProperty = "new value";
Assert.IsTrue(eventWasRaised);
That gives a minimal amount of plumbing. If you want to add some cleaning up, you can create a variable holding the event handler:
var sut = new SystemUnderTest();
bool eventWasRaised = false;
EventHandler eh = (s, e) => eventWasRaised = true;
sut.PropertyChanged += eh; // attach event handler
sut.AnyProperty = "new value";
Assert.IsTrue(eventWasRaised);
sut.PropertyChanged -= eh; // detach event handler
Although at first it seems like "unneeded plumbing" code adding a listener to the event is actually a good idea and I think you should do that to test the event.
There are some mocking frameworks that enable you to do just that you want but it adds additional dependencies to your code.
Keep it simple - subscribe to the event.
I agree with Fredrik Mörk's solution and use it fairly often. One note: it's best to insert a Sleep of at least 20-30 milliseconds after the triggering action to ensure that enough time is given for the event handler to kick in - sometimes I've had race conditions develop.