I am experiencing the almost same issue specified in this question. Can anybody please post the answer for this? The question is not answered in a clear way.
Issue with dynamically loading a user control on button click
In this aforementioned question, he is loading the control to a placeholder present in the first user control. My scenario is slightly different. My scenario is i have a single aspx page, UserControl1 and UserControl2. At the very beginning, I will load UserControl1 to Page. Then I need to unload userControl1 and load UserControl2 to Page when user clicks a button from UserControl1.
Events must be registered on page load not later. Your control is created during event handling and its event is not registered.
Take a look:
http://msdn.microsoft.com/en-us/library/ms178472.aspx
You need to create a custom event handler for UserControl1 and bubble the event up to the page when the button is clicked.
Create a custom event handler for UserControl1:
public event EventHandler UpdateButtonClick;
public void OnUpdateButtonClick(EventArgs e)
{
if (UpdateButtonClick!= null)
UpdateButtonClick(this, e);
}
Assign the event handler for the UserControl1:
<uc:UserControl1 ID="UserControl1" runat="server"
OnUpdateButtonClick="UserControl1_UpdateButtonClick" ... />
Handle the event in the code-behind:
protected void UserControl1_UpdateButtonClick(object sender, EventArgs e)
{
UserControl1.Visible = false;
UserControl2.Visible = true;
}
Related
This piece of code is in my ASPX page. The snippet shown below is used to dynamically load user controls based on certain selections made by the user on the ASPX page.
protected void loadUserControl(string tmUCName)
{
phDetail.Controls.Clear();
ViewState["vsControl"] = null;
UserControl tmUControl = LoadControl(tmUCName) as UserControl;
tmUControl.ID = "ucidControl";
phDetail.Controls.Add(tmUControl);
ViewState["vsControl"] = tmUCName;
}
The ASCX works, and so does the SELECT event on the ASCX page. My problem is getting the value from the select event on the ASCX page to the ASPX page. As the user control (ASCX) is loaded dynamically (based on certain selections on the ASPX page), I am finding it hard to wire the events from the ASCX into the ASPX page. In an explicit load situation, I have no problems... everything is pretty peachy...
For what it's worth, if the pages were explicitly loaded, example:
PlaceHolder1.Controls.Clear();
WebUserControlTest02 = LoadControl(#"~\WebUserControl2.ascx") as WebUserControl2;
WebUserControlTest02.gvASCX02SelectedIndexChanged += new EventHandler (WebUserControlTest02_gvASCX02SelectedIndexChanged);
PlaceHolder1.Controls.Add(WebUserControlTest02);
I have no problems with wiring events between ASPX and ASCX pages.
EDIT: There are two parts to the question and answer. The first part is how to "bubble" an event that occurs on a control inside the UserControl. This is accomplished by handling the inner control's event and then firing a similar event on the UserControl itself. In this case the UserControl's event shares the same name and signature as the inner control's event. This is not a requirement, but in this case it makes sense to do so.
The second part is how to dynamically load UserControls yet still have the containing web page hook up to this bubbled event that is defined on each of the UserControl classes. The problem is that the ASP.NET UserControl class itself does not define the event, and the only common aspect of the dynamically loaded UserControls is the fact that they are all of type UserControl.
This problem is solved by also having all of the UserControls implement a common interface that defines the event. By casting the UserControl variable to the interface type, you get access to the event that the interface defines. And at that time you can hook up the web page to handle the event.
Together, these two parts allow the event that originated in a ListBox control to be repeated by the UserControl that contains the ListBox, and for the web page which has dynamically loaded the UserControl to listen for and respond to the same event.
First define an interface with the event that you want handled:
public interface IMyUserControl
{
event EventHandler SelectedIndexChanged;
}
Next, have each of your UserControls implement this event and wire up the SelectedIndexChanged event of the listbox:
public partial class WebUserControl1 : System.Web.UI.UserControl, IMyUserControl
{
protected void Page_Load(object sender, EventArgs e)
{
ListBox1.SelectedIndexChanged += (o, args) =>
{
var selectedIndexChanged = SelectedIndexChanged;
if (selectedIndexChanged != null)
selectedIndexChanged(o, args);
};
}
public event EventHandler SelectedIndexChanged;
}
Now in your common code, cast the UserControl as the interface type and viola, you have access to the Event:
protected void loadUserControl(string tmUCName)
{
phDetail.Controls.Clear();
ViewState["vsControl"] = null;
UserControl tmUControl = LoadControl(tmUCName) as UserControl;
tmUControl.ID = "ucidControl";
phDetail.Controls.Add(tmUControl);
ViewState["vsControl"] = tmUCName;
((IMyUserControl)tmUControl).SelectedIndexChanged += OnUserControlSelectedIndexChanged
}
private void OnUserControlSelectedIndexChanged(object sender, EventArgs args)
{
// ...
}
I am creating a button dynamically in the PreRender event like this:
Button myButton = new Button();
myButton.Text = "Test";
myButton.Click += new EventHandler(myButton_Click);
myDiv.Controls.Add(myButton);
This button is render in the browser, but when I click the button, the click event doesn't fire. I tried to create an identical button in the PageLoad event and it works perfectly, but I must create this button it the PreRender event, since creating this dynamic button or not depends on a value which I get only in this event. What can I do so when I click a dynamic button created in the PreRender, the click event fires?
You should add your button to the page in the page's OnInit event and wire up it's click event during or before OnLoad and then you can enable/disable your button or make visible/invisible your button using the variable that you will have during the PreRender event. See Joel Coehoorn's answer to this question for more details. Otherwise try using a PlaceHolder control though that may end up being trickier.
protected override void OnInit (EventArgs e)
{
Button myButton = new Button();
myButton.Text = "Test";
myButton.Click += new EventHandler(myButton_Click);
myDiv.Controls.Add(myButton);
base.OnInit(e);
}
protected override void OnPreRender(EventArgs e)
{
myButton.Visible = myConditional;
base.OnPreRender(e);
}
Maybe create the button in the PreRender and bind the click event in PageLoad?
In PreRender you can create some var, which will tell you, that you need create button.
And on Render create that button by hand with need JavaScript or with sending form. But you can't use such simple syntax as +=EventHandler, more code need.
According to this link from MSDN, you must add button and event related to it if needed durign the OnInit() as explained here : MSDN Lifecycle
"Raised after all controls have been initialized and any skin settings have been applied. The Init event of individual controls occurs before the Init event of the page.
Use this event to read or initialize control properties."
To do so, try something like that :
protected override void OnInit(EventArgs e)
{
// Do some stuff here
base.OnInit(e);
}
You should move control creation earlier in the page lifecycle. Control events are fired after Load and before PreRender so OnLoad or anything earlier should do.
You should add the button on the preinit phase, otherwhise it won't fire
Asp net lifecycle
Use this event for the following (PREINIT):
Create or re-create dynamic controls.
I am creating an user control. The user control is a div and I want to add a click event to it.
Edit:
The page that has this control on it has to handle this event.
How can I do this?
First, you need to define an event on your UserControl that allows Page that contains the UserControl to register and handle the event. For example:
public partial class MyUserControl : System.Web.UI.UserControl
{
// Event for page to handle
public event EventHandler DivClicked;
protected virtual void OnDivClicked(EventArgs e)
{
if (DivClicked != null)
DivClicked(this, e);
}
protected void Page_Load(object sender, EventArgs e)
{
// Page Load Code goes here
}
}
Note:
The next part would be easier if you were using a control that supported postbacks. However, since you want to use a div, I'll explain how to force a div to do postbacks. I'd like thank Mathew Nolton for this solution.
So, in the Page_Load method of the UserControl you need add an onClick attribute to call the ASP.NET's __doPostback() javascript function that calls the server back for your div. This is what gives a div the ability to postback to the server. In addition, to determine which control caused the postback, I supplied the div's ClientId along with some symbols to differentiate my postback from other controls. Remember when you define the div on the .ascx file it has to have an id assigned and set runat="server", to be accessible on the server side.
Ok, now by adding an onclick attribute to the div, it will postback to the server anytime its clicked. So, when a postback causes Page_Load to get called, I check to see if it was the div which caused the postback. If so, I raise the UserControl's DivClicked event to be handled by the Page.
public partial class MyUserControl : System.Web.UI.UserControl
{
// Event Definition and Raising methods
...
protected void Page_Load(object sender, EventArgs e)
{
// #### will denote this is an argument I provided.
string arg = "####" + divClickableDiv.ClientID;
// Add postback method to onClick
divClickableDiv.Attributes.Add("onClick",
Page.ClientScript.GetPostBackEventReference(divClickableDiv, arg));
if (IsPostBack)
{
// Get event arguments for post back.
string eventArg = Request["__EVENTARGUMENT"];
// Determine if postback is a custom postback added by me.
if (!string.IsNullOrEmpty(eventArg) && eventArg.StartsWith("####"))
{
// Raise the click event for this UserControl if the div
// caused the post back.
if (eventArg == arg)
OnDivClicked(EventArgs.Empty);
}
}
}
}
That should do it for the UserControl, now all you have to do is register for the DivClicked event on the page.
Unfortunately, you wont get design time support to register for the event. However, you can still add the code to the .aspx page. On the page where you drop your UserControl add an attribute to the UserControl called OnXXX where XXX is the name event. So, for my example above i would define my UserControl on the page would look like this:
<uc1:MyUserControl ID="MyUserControl1" runat="server" OnDivClicked="MyUserControl1_DivClicked" />
Now you add your handler code to the Page's codebehind file (assuming your using codebehind) like this:
public partial class MyPage : System.Web.UI.Page
{
// Called whenever div in MyUserControl is clicked.
protected void WebUserControl1_DivClicked(object sender, EventArgs e)
{
// Handle Div click event here.
}
}
That should do it. I hope this post helps you.
<div runat="server" onserverclick="MyClickHandler">
...
</div>
Rocka's answer is close, but not quite right (as in it didn't work for me, and I figured out why).
The code bits for the Rocka's usercontrol are fine:
// Event for page to handle
public event EventHandler DivClicked;
protected virtual void OnDivClicked(EventArgs e)
{
if (DivClicked != null)
DivClicked(this, e);
}
When consuming the UserControl, the following will not work:
the OnDivClicked is not the event handler, it's a function, so you can't assign it. let alone, when the function fires, the actual event handler variable is null, so it's not going to execute anything.
The proper way would have been:
This would have assigned MyUserControl1_DivClicked to be the handler for DivClicked. Sadly, this wasn't actually working, so in the code-behind on the page's Page_Load, put this line instead:
this.MyUserControl1.OnClick += new EventHandler(MyUserControl1);
Also, as a side note, if you make the div be runat="server", then OnClick is exposed as an event that you could have hooked into. All you would have needed is a passthru property for EventHandler in the user control to the div.
In your ItemTemplate USE asp:Panel INSTEAD OF div tag (a panel renders as a div) and set the Visibility property like so:
<asp:Panel ID="ImgFeatured" runat="server" CssClass="featured-ribbon"> </asp:Panel>
Code behind
Panel ImgFeatured = (Panel)e.Row.FindControl("ImgFeatured");
ImgFeatured.Visible = true;
I have a simple user control that contains some buttons that fire events which I want to be handled by the page using the control. I have my code setup as such:
public event EventHandler Cancel;
public event EventHandler Confirm;
public void Confirm_Click(object sender, EventArgs e)
{
if (Confirm != null)
Confirm(this, e);
}
public void Cancel_Click(object sender, EventArgs e)
{
if (Cancel != null)
Cancel(this, e);
}
but when I try to call these from the page that is using the control's page load event I don't get any of the custom events
ASPX Code
<%# Register TagPrefix="btg" TagName="CustomControl" Src="~/Search/CustomControl.ascx" %>
<btg:CustomControl ID="btgControl" runat="server" ></btg:CustomControl>
could this be because my buttons in the user control are within an update panel?
You shouldn't be seeing methods. You should be seeing events.
In your parent page's load, you need to do this:
myUserControl.Cancel += new EventHandler(myUserControl_Cancel);
You can hit tab,tab to auto-generate the method stub. That will look like:
void myUserControl_Cancel(object sender, EventArgs e) {}
Then, this code will fire after it is called in the method of your user control. In order for that code to fire, you'll have to assign the events to button events on your user control.
edit: myUserControl is the id of your user control. Also, some would argue that event handlers should be in your page's init method.
edit:
Is your user control properly referenced in the page? i.e. Are you registering the user control in web.config or using the reference directive in the page?
Also, did you try cleaning the solution and rebuilding? If your user control is dynamically created/loaded, you'll have to wire up the events in the same scope as the instantiated control. In order to dynamically load the user control, you'll have to have a placeholder in your page and do the following:
UserControl control = Page.LoadControl("~/ControlPath/ControlName.ascx");
((MyUserControlClass)control).Cancel += += new EventHandler(myUserControl_Cancel); // etc...
In my child user control I have a gridview with an OnRowCommand eventhandler that is executed when Edit button is click. I want to set the visibility of an ASP.NET placeholder control in the parent to true when the Edit button is clicked in child control.
What would be the best way to accomplish this task?
Update:
After a little bit more research on the internets, I create a public event Eventhandler in my child control and rasied the event when the OnRowCommand event was fired. In my page_load event of my parent control, i mapped the child user control event to an private event in my parent control.
Child Control source code:
public event EventHandler MyEvent;
protected void MyGridView_OnRowCommand(object sender, GridViewCommandEventsArgs e)
{
if(MyEvent != null)
MyEvent(sender, e);
}
Parent Control source code:
protected void Page_Load(object sender, EventArgs e)
{
MyChildControl.MyEvent += new EventHandler(this.MyLocalEvent);
}
private void MyLocalEvent(object sender, EventArgs e)
{
MyPlaceHolder.Visible = true;
MyUpdatePanel.Update();
}
There are two methods in addition to bubbling the event worth considering:
a. Create a new event in your child user control. Listen to this event in the parent control. Fire this event in the child control.
b. Listen to the gridview event OnRowCommand in the parent control.
Approach a is superior because there is less of the abstraction leaking through. B is quick and dirty, but if this is a one-time-use user control, it will not have a negative impact.
Creating events is fairly easy, many programs include templates for events which mean they only thing you type is the name of the event (e.g. Resharper).
Off the top of my head I would either create a new event within the child user control that would fire off when OnRowCommand fires, or use OnBubbleEvent - I can't remember the exact name but it's something like that.