How to invoke events across User Controls in ASP.NET
I want my code to avoid all the middle men, to be foolproof with clear and visible usage, and to be simple to use. That suggests we should declare our events the usual way, all listeners should register themselves the usual way, there should be no more than one line of code to forward the event, and the forwarding should happen once.
So we need something to expose the events and methods to invoke them:
- Events and notification methods come in pairs.
- Notifiers and listeners use the same object.
- The object will keep track of the event handler delegates in
Context.Items.
In the provided code, I have one User Control with two buttons to invoke events, and another User Control to receive them. I used a regular Button and an ImageButton to demonstrate event handlers with different argument types.
The sender control uses the following code to invoke the events:
private ButtonEvents events; private void Page_Load (object sender, EventArgs e) { events = new ButtonEvents(Context.Items); } private void uxButton_Click (object sender, EventArgs e) { events.ClickButton(sender, e); } private void uxImage_Click (object sender, ImageClickEventArgs e) { events.ClickImageButton(sender, e); }
The receiver control uses this code to register to those events:
private void Page_Load (object sender, EventArgs e) { ButtonEvents events = new ButtonEvents(Context.Items); events.ImageButtonClicked += new ImageClickEventHandler(events_ImageButtonClicked); events.ButtonClicked += new EventHandler(events_ButtonClicked); }
The ButtonEvents class needs a little more work than usual to implement, but not much:
internal class ButtonEvents { private CachedEvent buttonEvent; private CachedEvent imageButtonEvent; public ButtonEvents (IDictionary items) { buttonEvent = new CachedEvent(items, "Button"); imageButtonEvent = new CachedEvent(items, "ImageButton"); } public event ImageClickEventHandler ImageButtonClicked { add { imageButtonEvent.Add(value);} remove { imageButtonEvent.Remove(value);} } public event EventHandler ButtonClicked { add { buttonEvent.Add(value);} remove { buttonEvent.Remove(value);} } public void ClickButton (object sender, EventArgs e) { buttonEvent.Invoke(sender, e); } public void ClickImageButton (object sender, ImageClickEventArgs e) { imageButtonEvent.Invoke(sender, e); } }
The ButtonEvents class makes use of the CachedEvent helper object. This is the object which implements the real solution. The CachedEvents takes a dictionary and a key in its constructor, so it knows where to store the event handlers. The event handlers are delegates, and are stored as such:
public CachedEvent (IDictionary items, object key) { this.items = items; this.key = key; } private Delegate Listeners { set { items [key] = value; } get { return (Delegate) items [key]; } }
There are two helper methods to register and unregister event listeners:
public void Add (MulticastDelegate newListener) { Listeners = Delegate.Combine(Listeners, newListener); } public void Remove (MulticastDelegate formerListener) { Listeners = Delegate.Remove(Listeners, formerListener); }
And finally, the method to invoke the event:
public void Invoke (object sender, EventArgs arguments) { Delegate listeners = Listeners; if (listeners != null) listeners.DynamicInvoke(new object[] {sender, arguments}); }
-
Recent
- How To Implement Custom Rounding Procedures
- How to count # of character occurrences in a string .NET vERSION
- How to count # of character occurrences in a string
- Easier way to manage your ASP.NET Cache
- Working with Dates and Time in ASP.NET
- How to invoke events across User Controls in ASP.NET
- HttpCacheVaryByParams Class
-
Links
-
Archives
- July 2009 (1)
- February 2009 (2)
- June 2008 (3)
- December 2007 (1)
-
Categories
-
RSS
Entries RSS
Comments RSS