Wait for event handlers to complete before continuing - c#

Let's say I have a user control named A that does the following:
Page_Load:
List<object> myList = PrepareList();
ListPrepared(this, new AArgs(myList)); // Event that lets subscribers modify the list.
OperateOnAndDisplayList(myList);
An instance of A is held in a page that subscribes to the ListPrepared event and modifies the list that's created. I want the page's handler to finish before I operate on and display the list, obviously, since it's modifying the list for completeness. How would I go about implementing this? (Or is this a horrible idea, since it exposes the list and thus requires outside elements to have knowledge of the list in order to modify it?)

Events are raised synchronously. This means that all subscribers to the event will execute their code before the OperateOnAndDisplayList method is called. This also means that if myList is modified by any of the event subscribers, the modification will be visible to the event publisher as well. If this isn't what you want, you should create a copy of the list before raising the event, and only send the copy with the event's EventArgs.

If the event handler is returning when all its code is done, that you don't have to worry about it. Events are just a way of invoking methods. It is not related directly to async operations.

Related

how to obtain Targets of an event

I have an event to fire, named ValueGenerated. The code that generates values and fires ValueGenerated is running in a thread and the method which recieves this event is on a form.control (i.e. a form). As UI thread does not allow another thread to change the UI I wrote the following code on the event generation:
if (ValueGenerated.Target is System.windows.form.control)
{
Control targetForm = ValueGenerated.Target as control;
targetForm.Invoke(ValueChanged,new object[]{this,args});
}
But I think what happens if the event is registered by more than one methode. For example, by two or three destinations. Why on the event and delegate classes we have just the Target property which returns the instance object of the last method added? Do we always need just the last one?
You're doing it wrong.
As noted in the comments, you can get the full list of invocation targets by calling GetInvocationList() on the delegate instance. Then you can invoke each target individually.
But this is not the right way to do it. Your event should treat all handlers the same.
If the event is the kind of event that is always raised in a background thread, and is always handled by a UI object, then it should always use an appropriate mechanism to dispatch to the UI thread. See the BackgroundWorker class for an example of this sort of design, specifically its ProgressChanged and RunWorkerCompleted events.
If either of those conditions are not true, then your event should not attempt to deal with the cross-thread invocation in any way. Subscribers to the event that have thread affinity should be expected to deal with that themselves.
Unfortunately, there's not enough context in your question to provide any more specific advice than that. The only thing that is clear is that you've started down a dead-end road. Turn around, come back, and take the smoother path. :)

Getting all the attached event handlers for a WPF control

I am developing an application where I assign the events for the button dynamically. Now the thing is that I wish to get all the events for the button click event as I wish to remove the previous handlers.
I tried setting the event handler to null like:
Button.Click += null;
However I received a runtime exception that null cannot be assigned.
I wish to know the events which are already attached to it so that I can remove those events.
Can anybody help me in achieving this?
You cannot assign events - only attach (+=) and remove (-=) operations are available for clients.
Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.
A nice pattern is to have an Action removeAll declared somewhere, so you can do:
button.Click += handler
removeAll += () => button.Click -= handler
That way you've only got one variable to keep track of, and you can clear everything just by calling removeAll(), rather than keeping track of all your handlers individually and having to call -= on each of them. It's especially convenient if you've got multiple subclasses of EventHandler to deal with, since otherwise you'd have to keep track of them with multiple lists.
You can't do that (fortunately. Just imagine, that some external code removes your event handler, and your code just stops working in silent manner).
(Reflection isn't an option here, because event implementation may be differ from type to type). Usually, if you want to remove all event handlers this way, this means design error.

Is there anyway to stop the flow of events in .NET?

that is a question I have been asking myself for a while.
Giving a certain flow of events, can I when handling one of them, stop the next ones to be raised?
For example, when collapsing a node which child was selected in a treeview (winform), the events are raised like that:
BeforeCollapse
BeforeSelect
AfterSelect
AfterCollapse
I could stop them by using a class member, but I was wondering whether there was a built-in function or just another way (a more elegant way) to achieve this, by acting directly on the events queue.
Any idea?
Not easily, no. The order of the events firing is controlled by the TreeView control class, and there is no built-in way to prevent events from firing. But you have a couple of options:
Create your own TreeView class that inherits from the base class,
then add a bool property to prevent the events from processing.
Then you can override BeforeCollapse, etc. to check the bool
before calling base.BeforeCollapse.
Just create a bool flag, and check the flag in each of the events.
No there is no way to do that for that type of event (you are asking for TreeView).
Like for example could be managed KeyEventArgs.Handled via built-in mechanism.
You can use some instance (boolean ?) value to manage the flow,
or you can, unsubscribe from the event that you don't want more recieve, but after subscribe to it again. Sounds rough solution, but sometimes turns out reasonable one.
even if the event are raised nothing will happen if you don't bind an event handler to them. In this case you can just remove the handler using the code below:
object.Event -= new EventHandlerType(your_Method)
Otherwise you should create your own custom control
according to OnBeforeCollapse you get an TreeViewCancelEventArgs which has an Cancel property. Setting this to true should stop the flow, but will also not collapse it.
Same goes for OnBeforeSelect.
The only times you can easily "cancel" an event is if the event handler has the CancelEventHandler delegate type. Even then it doesn't really cancel it as much as set a flag for the remaining events that makes it skip performing all the events subscribed to it.
If you did have a CancelEventHandler type (which these don't) you'd simply set Cancel to true on the event object itself in the handler.
Plenty of other answers give you suggestions for what you should o. I'd just go with your idea: set a 'event cancelled' flag in your control class, and check it. When the last event in the series gets called, reset it.

C# Should I manually remove the event handler I declared?

Okay, make an example here:
I have UserControl A, UserControl B, UserControl C and one Windows Form.
This Windows Form is only started with UserControl A.
UserControl C has [Next] and [Back] buttons.
Say, UserControl A is declared with an event handler. One of function in UserControl A will actually raise the event call to execute one function at UserControl C.
So, at UserControl C, I have to add with
"UserControlA.OneFunction += this.UserControlC_Function;"
If I click Next button at UserControl C, it will dispose the UserControl A and add new UserControl B to the Windows Form. But I never remove this event handler manually.
One of the function in UserControl A is the caller (where event is declared).
One of the function in UserControl C is the listener.
So, these are my questions:
Should I manually remove the handler before UserControl A disposed?
Will this User Control A dispose automatically remove the handler that declared previously?
Should I add this somewhere?
"UserControlA.OneFunction -= this.UserControlC_Function;"
By convention, we don't. And since no event should be invoked after disposal, there is no need to do so unless the control in question is behaving weirdly.
No. At least there isn't such code as seen from reflector.
You don't need to remove the handlers in this case because neither the form nor its buttons are referenced by code external to the form, and the entire object graph will therefore be garbage collected.
The answer to this post does a really good job explaining when you need to manually remove an event handler and when it is not necessary.
Do I need to remove event subscriptions from objects before they are orphaned?
If the form is released (assuming no other objects has a reference to the objects in question) there's little risk of not removing the event handler, however it's a good idea always to remove the event handler before the object listening can no longer be reach (ie all variables referencing the object i sout of scope) not doing so can create a memory leak.
This is not the case in your situation (if I get what you are describing, code would make it more clear)
The problem would be if you attach a delegate referencing object C to an event on object A and then looses access to C (e.g. assigning a new value to the variable). C would then hang around until A is garbage collected
If the memory lifetime of an event publisher is not limited relative to the useful lifetime of an event subscriber, failure to unsubscribe an event will likely cause a memory leak. Were it not for the unfortunate hassle of doing so, there wouldn't be any reason for an event subscriber that was being disposed not to unsubscribe from all events, and for an event publisher that was being disposed not to nullify all event subscriptions. Since neither C# nor VB provides any convenient means of doing those things, however, one has to balance the hassle of proper subscription handling with the fact that in many situations one can get away skimping on it.

C#: Create an event that is fired whenever another event that has listeners is fired, dynamically via reflection maybe?

Here's what I am working with:
Part of my project is a windows form app. I want to basically capture every event that fires and has listeners. So some button's click event, some checkbox's check event, everything on a basic "Control" event list. So that event still fires, but also fires my event.
Is there a generic "some event fired" event under the hood I can tap into, or is there a way using reflection to enumerate through all objects in my form, parse out all the events, parse which have listeners, and then subscribe all of them to a generic event elsewhere in addition to where they are already going?
Anyone know how to do this?
You fundamentally can't do this: an event is a black box with just "subscribe" and "unsubscribe" functionality. So while you can use reflection to find out all the events, you can't reliably detect which have been subscribed to. For field-like events you could fetch the backing field and check whether or not it's null, but even that's not reliable - to avoid null checks, the author may have written something like this:
public event EventHandler SomeEvent = delegate {};
For other events, you'd have to work out what subscribing to the event actually does - for example, it might use EventHandlerList.
Basically, you should rethink your design so you don't need to do this.
Doesn't the fact that a subscribed event got fired indicate it has subscriber(s)? So then all you would need is a list of subscribable events, which you can validate against during an intercepted call.
You can intercept a call using any AOP framework. For instance, by using Unity Interception, you can do something like this:
public IMethodReturn Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
{
// 1. assuming that you are keeping a list of method names
// that are being subscribed to.
// 2. assuming that if the event is fired, then it must have
// been subscribed to...
if (MyReflectedListOfSubscribedEvents.Contains(input.MethodBase.ToString())
{
HandleItSomeHow();
}
// process the call...
return getNext().Invoke(input, getNext);
}

Categories