As user controls are self-contained (and possibly dynamically loaded at runtime), we cannot directly reference the ID of any element that exists on a different page. One solution would be to subscribe to the child's button click event from the parent page, but this would break some of the object oriented rules of encapsulation.
A neater solution would be to publish an event in the user control. The parent page can then subscribe to this event. With ASP.Net, this functionality already exists, via the OnBubbleEvent and RaiseBubbleEvent methods. 'Event bubbling' using these methods allows a child control to propagate events up its containment hierarchy. I found these methods extremely easy to use, and it prevents the coder from having to explicity raise custom events and subscribe to these in different levels.
Lets see how it works...
In my child control, the 'OnClick' code behind of my button contains the following line:
RaiseBubbleEvent(sender, new
CustomClickEventArgs());
RaiseBubbleEvent sends the event data up the hierarchy to the control's parent. I've also included a custom EventArgs class - more on this in a bit.
To handle (or to further propagate the bubbled event, upwards) a control must override the OnBubbleEvent method. A control that has an event bubbled to it does one of the following three things.
- It does nothing, in which case the event is automatically bubbled up to its parent.
- It does some processing before continuing to bubble the event. To accomplish this, a control must override OnBubbleEvent and invoke RaiseBubbleEvent from OnBubbleEvent.
- It stops bubbling the event and handles the event.
/// <summary>
/// Handles the
RaiseBubbleEvent event
/// raised by a control
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
/// <returns>True if
event is handled, false if event needs passed to parent</returns>
protected override bool OnBubbleEvent(object
source, EventArgs e)
{
bool handled = false;
if (e is CustomClickEventArgs)
{
handled = true;
RefreshParentGridView();
}
}
return handled;
}
By returning true, I am preventing the event from bubbling up any further. Alternatively, I could execute some code in the method above and then return false. This would mean the event would bubble up to the next level which overrides OnBubbleEvent, and I would have performed some logic at each level.In the parent class, we will only have one instance of OnBubbleEvent being overriden. This poses a slight problem if we are calling RaiseBubbleEvent for multiple different events in different child controls - how do we know what logic to perform at the parent level that is specific to the event that has been raised? Easy...
In the above OnBubbleEvent method, I have added a clause which checks the type of EventArgs passed from the RaiseBubbleEvent call in the child. Based on the EventArgs, we can determine which logic to execute. I created a custom EventArgs class for the type of event I was raising:
/// <summary>
/// Custom Event Arguments
class
/// </summary>
public class CustomClickEventArgs: EventArgs
{
public CustomClickEventArgs()
{
}
}
We could even parameterize this custom event args class to expand the logic - for example - we could use the same class for one entire user control but have a parameter, passed to the constructor, which specifies which button on the user control was clicked, and then check this value in the OnBubbleEvent method to perform separate logic.
No comments:
Post a Comment