views:

232

answers:

4

Give the following control hierarchy on a ASP.NET page:

  • Page
    • HeaderControl       (User Control)
      • TitleControl       (Server Control)
    • TabsControl       (User Control)
    • other controls

I'm trying to raise an event (or some notification) in the TitleControl that bubbles to the Page level. Then, I'd like to (optionally) register an event handler at the Page codebehind that will take the EventArgs and modify the TabsControl in the example above. The important thing to note is that this design will allow me to drop these controls into any Page and make the entire system work seamlessly if the event handler is wired up. The solution should not involve a call to FindControl() since that becomes a strong association. If no handler is defined in the containing Page, the event is still raised by TitleControl but is not handled.

My basic goal is to use event-based programming so that I can decouple the user controls from each other. The event from TitleControl is only raised in some instances, and this seemed to be (in my head) the preferred approach. However, I can't seem to find a way to cleanly achieve this.

Here are my (poor) attempts:

  1. Using HttpContext.Current.Items

    Add the EventArgs to the Items collection on TitleControl and pick it up on the TabsControl. This works but it's fundamentally hard to decipher since the connection between the two controls is not obvious.

  2. Using Reflection

    Instead of passing events, look for a function on the container Page directly within TitleControl as in: Page.GetType().GetMethod("TabControlHandler").Invoke(Page, EventArgs); This will work, but the method name will have to be a constant that all Page instances will have to defined verbatim.

I'm sure that I'm over-thinking this and there must be a prettier solution using delegation, but I can't seem to think of it. Any thoughts?

A: 

Are you trying to do something along these lines?

R0MANARMY
It's similar! The main difference is that I don't have access to the TitleControl from the Page level since it's encapsulated inside HeaderControl. This means that I cannot wire up the event handler in the fashion that the article mentions. From any given `Page`, I can only directly access HeaderControl.
Ishan
I'm pretty sure you solve that by exposing the desired event from the Title page on the HeaderControl and bubble it manually (so to speak). The automatic way to do it is, I think, Routed Events (http://msdn.microsoft.com/en-us/library/ms742806.aspx) but I'm reasonably sure those are only available in WPF.
R0MANARMY
A: 

You could have the Page implement an interface that has the events on them. Then have the tab control see if the page implents the desired interface. If it does then hook up to the events.

Missed the part about the title control. The title control would also have to make itself known to the Page via an interface method.

You could then hook up the events at some point (perhaps the load event). This would of course only work if the controls where added to the page prior to the load event.

Daniel
+1  A: 

To make each control reusable and decoupled from other controls, I've always taken this approach: Each container will know about the controls that it contains one level deep, but not about the container containing it. To communicate up, you are correct in using events. This provides your layer of abstraction and makes all of your controls reusable.

That being said, let's take a look at your example. Your TitleControl does not contain anything, so all it will do is fire events.

Your HeaderControl references your TitleControl and handles it's events. If it doesn't completely handle your TitleControl's events, then have it declare and fire it's own event, and pass along the original sender and event args.

At your page level, your page will handle your HeaderControl's events. Since your page is also the container for your TabsControl, call a public method in your TabsControl inside the event handler for your HeaderControl's event and pass in the bubbled up EventArg information.

Basically, use events to bubble things up, and use public methods or properties to push things down.

Aaron Daniels
Thanks for the answer, Aaron! This will work (and follows the same direction that Daniel was moving towards) and it's a perfectly suitable solution. I was wishing/hoping that there would be cleaner method that didn't involve touching HeaderControl, for example a single event that propagated to the Page level (root container) automatically.
Ishan
A: 

The HeaderControl can expose an event that gets consumed by the TabsControl. I've answered a similar question before (with a sample project attached).

devstuff