Am I using the right approach to oversee the tasks that I want to accomplish when creating a handle?

Is there a generally accepted best practice for creating an event handler that unsubscribes itself?

For example, the first thing I came up with is something like:

// Foo.cs // ... Bar bar = new Bar(/* add'l req'd state */); EventHandler handler = new EventHandler(bar.HandlerMethod); bar.HandlerToUnsubscribe = handler; eventSource.EventName += handler; // ... 



 // Bar.cs class Bar { /* add'l req'd state */ // .ctor public EventHandler HandlerToUnsubscribe { get; set; } public void HandlerMethod(object sender, EventArgs args) { // Do what must be done w/ add'l req'd state ((EventSourceType)sender).EventName -= this.HandlerToUnsubscribe; } } 



Saying this sounds hacky / bad is an understatement. It is closely related to time dependence ( HandlerToUnsubscribe must be assigned the exact value at the exact time). I feel that in this case I have to play the role of a complicator - is there something stupid or simple that I am missing?

Context:

I am creating a binding between the user interface and the proprietary command infrastructure in Winforms (using the useful ICommand in System.Windows.Input). One aspect of the binding infrastructure is that users who create a binding between a component of a UI command (for example, a toolbar button or menu item) are able to listen to the CanExecuteChanged command and then update the state of the user interface based on this - usually setting the Enabled property true or false .

The technique usually works quite well, but there are ways to trigger the event before creating the ui component descriptor. I am trying to ensure that the provided handler will not be launched if the handle has not been created. As a result, I consider providing a common helper class (" Bar ") that will facilitate implementation. The purpose of Bar is to check if an appropriate descriptor exists. If so, great! If not, it will subscribe to the corresponding IsHandleCreated event IsHandleCreated that the handlers included in the package will be launched when the handle is created. (This is important b / c, the client can set its bindings in the UI.ctor before the descriptor exists.) I want this subscription to be completely transparent, and therefore I also want each event handler to automatically unsubscribe itself from IsHandleCreated after completion work.

I'm still at the point where I'm trying to figure out if this is a good idea, so I haven't generalized the concept yet. I applied it directly to ToolStripItems in this case to check what the idea sounds like. I have not sold it yet.

I understand that I also have the opportunity to simply indicate that bindings can only be created after creating the user interface handle in the OnLoad event of the form (for example,). I know this can work, I have done this in the past. I would like to see if I can facilitate this particular requirement in this case. If it’s even practical.

+6
c # event-handling
Oct 12 '09 at 14:14
source share
8 answers

Greg

You do not have an observer pattern, but rather a message queue. Thus, you are using the wrong design pattern for the problem you are trying to solve.

It is easy enough to implement your own message queue from scratch using Queue{Action{object}} , where objects are placed in the queue, and you simply deactivate the elements when they are called.

+11
Oct 12 '09 at 14:43
source share

The usual way is to keep a boolean as to whether it should start ...

 bool runMyEvent = true; void Handler(object sender, EventArgs e) { if (runMyEvent) { // handler here runMyEvent = false; } else { return; } } 
+1
Oct 12 '09 at 14:23
source share

what about a handler that runs only once? Something like that:

 if (wasRun)
     return
 wasRun = true;

+1
Oct 12 '09 at 14:24
source share

You can use the run once method here, mentioned here several times, but there are a couple of problems with this, depending on your use case.

1) You might want to reconnect the method later and run it again. Although I suppose you can reset your bool

2) You still have this link, which may result in storing your class in memory instead of garbage collection.

One option is to use an anonymous method and close when defining event handling:

 public class Foo { public EventHandler<EventArgs> MyEvent; public void FireEvent() { if(MyEvent != null) MyEvent(this, EventArgs.Empty); } } Foo obj = new Foo(); Action<object, EventArgs> action = new Action<object, EventArgs>((sender, args) => { // We're now running the event handler, so unsubscribe obj.MyEvent -= new EventHandler<EventArgs>(action); // Do whatever you wanted to do when the event fired. }); obj.MyEvent += new EventHandler<EventArgs>(action); 
+1
Oct 12 '09 at 14:34
source share

If that makes sense (and if you have access to the code that calls the handlers), perhaps you could just delete all the events after running the handler ,

I don't know if this is a good idea, just another thought.

0
Oct 12 '09 at 14:20
source share

You can use WeakReference objects to introduce weak subscribers, so to speak. During the dismissal, you can check whether a weak link has already been collected or not, and remove this subscriber from the list of subscribers, if necessary.

The basic idea is that when subscribers gather the GC, your handler will notice this and drop them from the list of subscribers.

0
Oct 12 '09 at 14:26
source share

There is a detailed CodeProject article: Weak Events , which discusses several solutions to this problem.

0
Oct 12 '09 at 14:39
source share

I usually do something like the following to implement the event handler 1 time.

 void OnControlClickOneTime(this Control c, EventHandler e) { EventHandler e2 = null; e2 = (s,args) => { c.Click -= e2; e(s,args); }; c.Click += e2; } 
0
Oct 12 '09 at 15:31
source share



All Articles