Say. An essential component to re-use is encapsulation. Without encapsulation of the inner-workings of a class, you're liable to have serious problems when it comes to maintenance and ease of re-use. For anything but the simplest of components, you're component is going to need to notify it's container by raising events. So, if you're going to create re-usable ASP.NET UserControls, you're going to need to know how to create and consume events.
Unfortunately, many ASP.NET developers don't implement events from their user controls. I think there's one big reason for this, and the problem lies in the Visual Studio IDE. Visual studio does not automatically add a protected member variable for UserControls that are dropped onto and ASCX or ASPX control. I have no idea why this was left out of the IDE, but I have a suspicion that it's led to developers not properly encapsulating their User Controls. Since there's no automatic member variable, often controls are not thought of as components, like any other control on a web form.
Fortunately, there's a real easy way to solve this. Say you drop a UserControl called MyControl.ascx onto another user control. If this is the first control of this type dropped onto this control the control will be named MyControl1 in the HTML source. The key to accessing events and other properties of this control is to add a member variable. To add a member variable to the container class, you can simply add the line (C#):
protected MyControl MyControl1;
... to the top of your container control's code behind. Okay, so what does this do for us? Well, now, we've got a control that we can communicate with, without doing Page.FindControl. More importantly, we can easily wire up events that are raised in the child control and handle them in our parent! Now, we're able to encapsulate the inner-workings of the child control and notify the parent when something interesting happens.
So, very quickly, there are two essential methods to have a handle on for raising events. First, if you just need to notify the parent control that something happened, use standard System.EventHandler. This is cake. Simply define your event as a public member, like so:
public event System.EventHandler TabClicked;
Raise it whenever you want like this:
// Raise the tabclicked event.if(this.TabClicked != null) this.TabClicked(this, new EventArgs());
Then in your containing class you wire up the event like so:
this.MyControl1.TabClicked +=new EventHandler(MyControl_TabClicked);
Where MyControl_TabClicked is a method with a signature that looks like this:
private void MyControl_TabClicked(object sender, EventArgs e){}
Simple! Even cooler, if you type “this.MyControl.TabClicked +=” in the IDE, an press TAB twice, VS will wire up the event handler and create your method for you!Now, say you wanted to pass some specific data to the container control. One way is to use a delegate. This comes in really handy, and is in fact quite easy too. For example, what if you wanted to pass some private value from the encapsulated child class? First create a custom class deriving from System.EventArgs with a member variable that contains your interesting private value:
public class TabClickEventArgs : EventArgs{ private String myString; public String MyString { get { return myString; } set { myString = value; } }}
Then create a delegate for your event like so:
public delegate void TabClickEventHandler(object sender, TabClickEventArgs e);
The rest is just like before, except that you define your custom event hander, instead of the basic System.EventHandler.
public event TabClickEventHandler TabClicked;
And raise it like so.
// Raise the tabclicked event.if(this.TabClicked != null) { TabClickEventArgs e = new TabClickEventArgs(); e.SomeString = “test“; this.TabClicked(this, e);}
Finally, when you wire the event up, your method signature for the handler, just needs to match the signature of your delegate:
private void MyControl_TabClicked(object sender, TabClickEventArgs e) {}
This stuff is so easy and essential, that I can say with certainly that if you're doing ASP.NET development, and not raising events from your UserControls, you're probably not getting the maximum reuse out of your controls.
-Brendan
[Advertisement]
So you put the "protected MyControl MyControl1;" line in the page that you drug the user contron onto. Seems to me this merely declares a variable MyControl1 as type MyControl. This MyControl1 variable will be set to null.
Normally to use a class you must instanciate it. So you would write the line "MyControl1 = new MyControl();". If you do this, the reference that is shoved into variable MyControl1 is for an entirely new instance of the control (not the one you want. You want a reference to the user control that you drug onto your page.). How do you do this?
cjrice@tva.gov
Jeff,
You no longer need to do this with ASP.NET 2.0, in 1.1 this was necessary to get access to the instance of MyControl that was created by the runtime.
Awesome! Thank you.
Saved at least a days work
Article is too good.. Only the mistake is in wiring the event it should be
Thanks Brendan for nice article !
Pritam, you are correct sir!
so simple and yet so effective this saved me a lot of reading/searching
thanks alot brendan very much appreciated
Hi Btompkins
I will again reapeat what Jino has said, and will be thankfull and appreciate if you or somebody take some take time and explain it in more detail so that the newbie like me and others can also used this. Thanks in Advance
Anil.
***********Jino said **********
Jino said:
Hi there,
I have been looking for a solution to get my user control events fired. This blog has helped many people and I think it is gonna help me too. But I am a newbie and also I develop in Vb.net. Even though there is a translation in one of the posts, it didnt make things very clear to me. I understand the concept of creating the instance of the control in the parent control and transferring the handling of the event to the parent.
The name of the control mentioned in the article above - 'MyControl1' - is this the 'ID' of the user control inside the <form> tag of the Parent Control HTML ?
Being a newbie, I couldnt figure out which parts of code goes where. There are too many places to put the code snippets in - User Control HTML, USer Control Code Behind, Parent Control HTML and Parent Control Code Behind. Can someone take the pain of explaining this article a little further so that I can also try this magic nd make my user control events work?
I am sure a lot of newbies would appreciate this effort. I see the same questions raised in many other forums ending up in unsatisfactory or not so detailed answers.
Thanks very much in advance. Someone please take the time. We are looking upto u guys for ur expertise.
Jino
Hi
i am unable to register the event. do i need to use InitializeComponent() to register the event below? (I am using vs2005)
I used "this.MyControl1.TabClicked +=new EventHandler(MyControl_TabClicked)" but
the TabClicked always giving me null.
am i doing anything wrong? anybody who experienced this please reply back.
-Gopala
Hi, I figured it out.
Use OnInit method on your containingpage and initialize the user control and event there. Just like below
protected override void OnInit(EventArgs e)
{
mypager.ItemClicked += new ItemClickEventHandler(this.HandlePagerEvent);
mypager.EnableViewState = true;
base.OnInit(e);
}
The problem i faced before is on postback, the Properties of control were becoming null. so is the event and unable to raise it. OnInit takes care of this.....
thanks
-Gopal
Awesome! Incredibly simple and infinitely useful. Thanks for posting this!
Nice article, I'm using this since asp.net 1.1, but I've some comment for asp.net 2.0 / vs2005, maybe it helps.
... "Visual studio does not automatically add a protected member variable for UserControls that are dropped onto and ASCX or ASPX control" ...
I think this is true only for the "web site" project model. In the wap ("web application project model"), we get the protected member automatically in the "aspx.designer.cs/aspx.designer.vb" partial class.
With WAP:
protected MyControl MyControl1;
not needed in the code behind, because already declared in the partial class!
But there is a small problem with this automation:
What if my page is inherited from a base class and I want to declare MyControl1 in the base class? If I simply put the declaration in the base class, we could get warning CS0108! In that case we can delete the declaration in the designer file, and the IDE will not add declaration again (until the same declaration remains in the codebehind class, or in a base class).
What do you think?
Some explanation for Jino :) (only .net 2.0)
We have an aspx page with a codebehind file.
And we have a usercontrol: an ascx file with also a codebehind file.
You drop your usercontrol to the aspx in design view or manually (I prefer this) add it in source view.
a) MyControl1 is the id of the usercontrol in the asPx file.
b) protected MyControl MyControl1; needs to move in the asPx's codebehind. In WAP you doesn't need this see the previous comment.
c) public event System.EventHandler TabClicked; go to the asCx's codebehind.
d)
if(this.TabClicked != null)
this.TabClicked(this, new EventArgs());
also could be in any function in asCx's codebehind. This raises the event.
(In fact by the .net event declaring "rules", this should be called from a protected virtual function OnTabClicked( EventArgs e ) { ... }, but doesn't care about this now.)
e) this.MyControl1.TabClicked +=new EventHandler(MyControl_TabClicked);
should be in the asPx's codebehind that way:
protected override void OnInit(EventArgs e)
{
this.MyControl1.TabClicked +=new EventHandler(MyControl_TabClicked);
base.OnInit(e);
}
f) private void MyControl_TabClicked(object sender, EventArgs e){} should be in the asPx's codebehind, this handles the usercontrol event.
g) The rest of the article show you how to fine tune your event (sending additional info) in the usercontrol, by declaring a custom delegate.
hope this helps.
You don't need to declare the child control as ASP.NET does this for you when you include the control in the page - you will already have a local object called MyControl1 if you give it that id, eg:
<MyTagPrefix:MyControl
Then you can just use the public properties of your control when the event fires:
private void MyControl1_EventFired(object sender, EventArgs e)
{
//set the value of a text box as an example
ATextBoxOnTheContainingPage.Text = MyControl1.PublicProperty;
}
Ok...I have a series of user controls which inherit from a base class that has an event defined in it. Each of these is sitting on a page (5 of them right now). When a change is made in a datagrid in any one of the user controls the page needs to respond. The user control raises the event but I can't get the page to see the event. Likewise, there is an event that the page raises when a selection is made in a dropdown or two but I cannot get the user controls to see that page level event.
How and where should these events be defined (I'm using VB.NET) so that UC's and Page can see the others events and live happily ever after? Any ideas?
Great article! Thanks for the straight forward explanation.
In my case I used an event that was published from a User Control via a Master Page to a Page.
- Leif
Gr8..!!!!
Thanx 4 saving lots of my time and showing me good way to use events in user control.
Dear Sir,
I want to fire the custom event from user control (c#) so , please if u have any sample code then send me it on this mail id deo_bhushan@yahoo.com
I have been doing this before but have a question...
How come I cannot do the event subscription from the code front (i.e. aspx) like what you can do with server controls?
It would be nice if you can do TabClicked="MyControl_TabClicked" in the aspx rather than code.
BTW, I found a work around to this problem ;)
My thanks join the many others. Jsut to make it even easier for some, here is all you need to do in ASP.NET 2.0 with VB.net:
in control:
Public Event MyEvent As System.EventHandler
(do this in whatever sub or func as needed)
RaiseEvent MyEvent(Me, New EventArgs())
and in container:
Protected Sub MyControl_MyEvent (ByVal sender As Object, ByVal e As System.EventArgs) Handles MyControl.MyEvent
'do something
End Sub
Pingback from Bob’s World of Code » Blog Archive » Create A User Control
Thanks - this described just enough to get me started - now I'm going to apply this technique across my entire project (well, at least where it's applicable). Thanks again!
You can also use another approach by overriding the accessors of the event :
public event EventHandler onButSavClicked
add { butSave.Click += value; }
remove { butSave.Click -= value; }
This saves some typing since you dont have to implement the event in the user control that just throws it again, don't have to check for null and don't have to add fe. Onclick event on the usercontrol.
Tom Pester, you are a legend. Cheers dude. So glad I scrolled to the bottom to check for sample code. :)
Thank you for the write up. It's nice to see it done so simple.
thank you!
This is probably the only article that has ever explained this properly - Legendary!
Pingback from raising events in a user control ??? | keyongtech
What if you are loading in a user control dynamically like I am. how do I wire up my events then?
Dim Job_Details As UserControl = LoadControl("~/JobDetails.ascx")
Job_Details.ID = "Job_Details1"
AddHandler Job_Details.Results_LoadTab_JobDetails, AddressOf what goes here???????
'parent control housing dynamically created control
RaiseEvent Results_LoadTab_JobSeekerDetails(JobID)
'this is in my usercontrol
Public Sub Load_JobDetails(ByVal JobID As Long)
'Do all the cool stuff here
'but how do i call this?
End Sub
Yesterday evening, I found the design solution to my problem and it was effectively to encapsulate the functionality of my User Control and raise special events.
My little brain kept ticking in the background because I was not sure how to implement this and I (try to) make a rule of not working week-ends...
This article is just simply brilliant!
Just the answer I needed. I'll be able to relax for the week-end now
Thanks
:-)
Couldn't be easier. Thanks for a concise and understandable explanation.
Hi... just curious... you have a public property called "MyString" ... but then later use this class and assign the property "e.SomeString." ...small detail, but shouldn't that be "e.MyString?" ...or am I incorrect?
public class TabClickEventArgs : EventArgs
private String myString;
public String MyString
if(this.TabClicked != null)
{
TabClickEventArgs e = new TabClickEventArgs();
e.SomeString = “test“;
this.TabClicked(this, e);
Cheers,
Jake
Easily Raise Events From ASP.NET ASCX User Controls
Really A good post
Good Brain on you. Clear & Concise.