Sometime we need that all our user controls should communicate to each other when they are on a page. The functionality can be achieved by putting a delegate instance on the user control and on the other user control create a target as following (suppose you have a UserControl AddEditUser.ascx and the page on which you put this user control has user listing and you want that whenever a user is added the Grid must be refreshed. So let's do it using aforesaid approach. Below is the code in the UserControl for the AddEditUser.ascx)
delegate void UserAction(object sender,EventArgs e);
public event UserAction OnUserSaved;
protected btnUserSave_Click(object sender,EventArgs e){
if(OnUserSaved != null)
OnUserSaved(sender,e);
}
And in the aspx page you write following code
AddEditUser1.OnUserSaved =
new UserAction(UserAdded_PageTrigger);
// OR this short hand..
// AddEditUser1.OnUserSaved = UserAdded_PageTrigger;
protected UserAdded_PageTrigger(object sender, EventArgs e)
{
// Time to refresh the Users' List.
}
But let's think broader. I want this UserControl can talk about this recently added user to other UserControls on the page (like a small dashboard showing total users we have or kind of). There is a popular content management solution that call this UserControl a Module. And this functionality is addressed there ( is called Intra module communication) using the Interfaces. A interface is one that a developer has to implement (all methods) so it needs a guideline for a new developer to how to implmenet the interfaces so that his/her module can participate in the module communication.
I tried this using BaseClasses ( BaseClass is not something special but still famous among developers with this name. It is a class that inherits System.Web.UI.Page and this class is then inherited by all the pages in the application so that if, later on there is something to be applied on all the pages of the system this class can help us.). Let's look at the classes first.
// BasePage.cs ( base class for all pages)
public class BasePage : System.Web.UI.Page{
private List<BaseUserControl> _participants;
public void Register(BaseUserControl me)
{
if (_participants == null)_participants = new List<BaseUserControl>();
_participants.Add(me);
}
internal void BroadCastToRegistrants(
BaseUserControl triggeringControl,
ControlBroadCastEventArgs e
)
{
if (_participants !=null)
foreach (BaseUserControl _control in _participants)
{
if (_control != triggeringControl) _control.SomethingHappened(triggeringControl, e);
}
}
}
// BaseUserControl.cs ( base class for all user controls)
public class BaseUserControl : System.Web.UI.UserControl
{
public delegate void BroadCastEvent(
BaseUserControl fromControl, ControlBroadCastEventArgs e);
public event BroadCastEvent OnBroadCastDetected;
protected override void OnLoad(EventArgs e){
base.OnLoad(e);
RegisterToPage();
}
protected virtual void RegisterToPage(){
((BasePage)this.Page).Register(this);
}
public void SomethingHappened(
BaseUserControl triggeringControl,
ControlBroadCastEventArgs e)
{
if (OnBroadCastDetected != null)
OnBroadCastDetected(triggeringControl, e);
}
public virtual void BroadCast(ControlBroadCastEventArgs e){
((BasePage)this.Page).BroadCastToRegistrants(this,e);
}
}
public class ControlBroadCastEventArgs : EventArgs
{
private string _message = string.Empty;
private string _sender = string.Empty;
private object _object =null;
public string Message { get {return _message;}set{ _message = value;}}
public string Sender{get{return _sender;}set{_sender = value;}}
public object Value{get {return _object;}set{_object = value;}}
public ControlBroadCastEventArgs(){}
}
A very simple approach
to use but some questions might arise. like
Q : Why ControlBroadCastEventArgs ?
A : This is the broadcast message. You can extend this message like you can add a DateTime type property that holds the timestamp when the broadcast occured.
Q : Why virtual methods ?
A : Nothing special but in case you want your user control must inherit the above BaseUserControl but should not participate in broadcasting or receiving broadcasts then just override this the Register method and write nothing inside. Or same way like if you want that your control only should listen to the outer broadcasts but should not broadcast anything then override the broadcast and put nothing inside.
Now let's take a look what will be inside your user control that you will inherit from the above BaseUserControl
To listen to a broadcast
protected void Page_Load(object sender, EventArgs e) {
this.OnBroadCastDetected +=new BroadCastEvent(ThisControl_OnBroadCastDetected);
}
public void ThisControl_OnBroadCastDetected (
BaseUserControl fromControl, ControlBroadCastEventArgs e)
{
if (e.Sender == "Broadcaster"){// process the broadcasted message (e);}
}
// to broadcast use following method
protected void BroadcastButton_Click(object sender, EventArgs e)
{
ControlBroadCastEventArgs ev = new ControlBroadCastEventArgs();
ev.Message = "New date selected";
ev.Sender = "CalendarControl";
ev.Value = Calendar1.SelectedDate;
BroadCast(ev);
}
Using the above approach any control can broadcast anytime (means from any event) and other controls can listen to it. Any number of controls can be participants to listen to above broadcast.