I have an .aspx page that dynamically creates multiple user controls, each of which have their own code behind which fires based on several events at the user control level. The problem is, before the events fire in a particular user control, the parent page Load method fires as well. Because each of the controls are added dynamically, this isn't a trivial amount of processing since each control must be re-added.
I'd like to be able to fire UserControl events without forcing an update on the page that hosts it. I've tried putting the entire user control in an UpdatePanel, but postbacks within the user control still force a page load for the parent.
Here's some test code with certain parts omitted and the control added declaratively, instead of programmatically.
.ASPX Parent Page
<%# Page Language="vb" CodeBehind="MyParent.aspx.vb" %>
<%# Register TagPrefix="uc" TagName="Control" Src="MyControl.ascx" %>
<form id="form1" runat="server">
<asp:ScriptManager runat="server"></asp:ScriptManager>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<uc:Control ID="Control1" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
.ASCX User Control
<%# Control Language="vb" CodeBehind="MyControl.ascx.vb" %>
<p>Control Added</p>
<asp:Button runat="server" Text="ForcePostBack"/>
This is how the ASP.NET WebForms page life-cycle works. Controls that postback will cause the host (read: parent) page to go through its Page_Load. If you do not like this model, then you should consider ASP.NET MVC or a client-side solution where you can make AJAX calls to acquire data and then do client-side rendering via templating logic.
Can you avoid it by having a Session variable like 'IsFirstLoad', then render the UCs only when IsFirstLoad is null (or true)?
Also, I've found that items rendered in Page_Init dynamically will persist through PostBack, so you wouldn't have to re-render. Don't know if that applies to UCs or not, though.
Related
Hi I am trying to use AjaxControlToolkit's Accordion control in user control. That user control is added to page dynamically from code behind. My code for user control is as follows:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MyControl.ascx.cs"
Inherits="Project.UC.Control" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="asp" %>
<asp:Accordion ID="Accordion1" runat="server" HeaderSelectedCssClass="Sel"
HeaderCssClass="unSel" SelectedIndex="0">
<Panes>
<asp:AccordionPane runat="server" ID="AccordionPane1">
<Header>Red Orchid</Header>
<Content>Some content here.</Content>
</asp:AccordionPane>
</Panes>
</asp:Accordion>
To add user control dynamically I used following code in my page's code behind
Control mycontrol = this.LoadControl("~/myUserControl.ascx");
this.Controls.Add(mycontrol);
On my user control consumer page I have form tag with runat="server" also added ScriptManager control for ajax functionality. When I run my code I am getting following error
Control 'ctl02_Accordion1_AccordionExtender' of type
'AccordionExtender' must be placed inside a form tag with runat=server.
I already used form with runat="server" tag on my consumer page why this problem is coming. To solve this problem I moved my consumer page's form tag to user control this solves my problem but by doing this I can't take advantage of postback on my consumer page. If I put form tag with runat="server" in both user control and consumer page it show error that you can use only one form tag on page. How to solve this problem.
Thanks in advance..
Add a PlaceHolder control onto a form and instead of this.Controls.Add(mycontrol); use PlaceHolder1.Controls.Add(mycontrol);
Or you need to add controls to form's Controls collection. In assumption that form has aspnetForm id you should write: aspnetForm.Controls.Add(mycontrol);
The reason is that Page class has own Controls property thus this.Controls.Add(mycontrol); line add control to Page.Controls collection. But all controls those submit any data to server must be placed in form element otherwise theirs values shouldn't be accessible on server side. This follows from html forms mature: HTML Forms and Input
I have a very simply web page with ViewState disabled everywhere:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="test" EnableViewState="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" EnableViewState="false"></asp:TextBox>
<asp:DropDownList runat="server" id="mylist" EnableViewState="false">
<asp:ListItem>my item 1</asp:ListItem>
<asp:ListItem>my item 2</asp:ListItem>
<asp:ListItem>my item 3</asp:ListItem>
<asp:ListItem>my item 4</asp:ListItem>
<asp:ListItem>my item 5</asp:ListItem>
<asp:ListItem>my item 6</asp:ListItem>
</asp:DropDownList>
<asp:Button runat="server" Text="click me"/>
</div>
</form>
</body>
</html>
Code behind
public partial class test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Dropdown list value is " + mylist.SelectedValue);
}
}
As you can see, no viewstate is enabled but it does preserve controls values, see here for the running example http://www.yart.com.au/stackoverflow/viewstate/test.aspx
Edit
latr0dectus has somewhat answered my question below. But what's an example where ViewState is required practically? I can't see what you need from the form other than control values.
#Petras: ViewState is not required to preserve control values so what does it
do?
Controls that implements IPostBackDataHandler uses LoadPostData() method to assign to some properties.
Read this article : Understanding ASP.NET View State
It is a common misconception among developers that view state is
somehow responsible for having TextBoxes, CheckBoxes, DropDownLists,
and other Web controls remember their values across postback. This is
not the case, as the values are identified via posted back form field
values, and assigned in the LoadPostData() method for those controls
that implement IPostBackDataHandler.
I'm not really sure what your question is.
View state is used in the page lifecycle. After the page is served it is destroyed on the server. Then the browser posts back it also posts back the viewstate. The server can use this in combination with the posted form values to recreate the previous state of the page and then show the changes.
In some cases even with viewstate disabled certain controls will appear to work as if they have viewstate enabled. This is because some controls have what is called "Control State". It operates almost like viewstate, except it cannot be disabled. This is because some controls would cease to function properly without it.
In the example you posted I think you are observing that the selected value of the dropdown is being posted to the server during postback. Not that it was reconstructed from viewstate.
Im adding this information that I found from the following link:
http://aspnetresources.com/articles/ViewState
What's the moral of this story? You don't always need view state enabled to maintain page state. "When do I need it though? What's it for then?" Glad you asked. The prime candidates for participation in view state are those controls that don't post back with the HTTP form and controls added or populated dynamically.
Scan to that part of the document and you should find what you are looking for.
I am developing my first asp.net website, my requirement is to refresh DropDownListB at SelectedIndexChanged event of DropDownListA, I have set AutoPostBack="True" for DropDownListA. Now the problem is whole web page gets refreshed, its unnecessary for me, is there any other technique that i can use to refresh only that control or only that panel rather than refreshing whole page?
Put the dropdowns inside
<asp:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
// Dropdowns
</ContentTemplate>
</asp:UpdatePanel>
and include <asp:ScriptManager ID="sm" runat="server"></asp:ScriptManager> at the top
1- You can simply place the dropdown in an UpdatePanel, this will avoid a complete post back.
You can get more details on UpdatePanel here
2- You can use jQuery AJAX to fetch the data in JSON format and bind it to the dropdown list, this approach is more efficient but little complex in comparison to UpdatePanel
You can find so many articles on this if you search this on google , like
[EDIT]
You can find a similar implementation here
I'd like to set the trigger of an UpdatePanel to a user control outside the UpdatePanel on the same page . The user control is added at design time, not at runtime.
If I statically declare the trigger, I get an error "A control with ID 'xx' cannot be found for the trigger in UpdatePanel". I tried to add the trigger at runtime in Page_Init or Page_Load, but it fails with the user control being null, although it has ViewState enabled. Has someone an idea on how to solve this?
Here is the code of the user control:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="ComponentDropDownControl.ascx.cs" Inherits="ComponentDropDownControl" EnableViewState="true" %>
<asp:DropDownList ID="ComponentDropDown" runat="server" DataSourceID="ComponentFile"
DataTextField="name" DataValueField="name" OnSelectedIndexChanged="ComponentDropDown_SelectedIndexChanged" AutoPostBack="True" EnableTheming="True">
</asp:DropDownList><asp:XmlDataSource ID="ComponentFile" runat="server" DataFile="~/App_Data/Components.xml" XPath="//component"></asp:XmlDataSource>
And here it is in the aspx page:
<%# Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="create.aspx.cs" Inherits="create" Title="Create task" %>
<%# Register Src="ComponentDropDownControl.ascx" TagName="ComponentDropDownControl"
TagPrefix="uc1" %>
...
<uc1:ComponentDropDownControl ID="CustomComponentDropDown" runat="server" EnableViewState="true" />
In the Page_Load function of the aspx page, the following lines work at first time, but fail on the first PostBack (line 2, CustomComponentDropDown is null).
AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
trigger.ControlID = CustomComponentDropDown.UniqueID.ToString();
UpdatePanel1.Triggers.Add(trigger);
EDIT: user control is not instanciated because it is cached. In fact, it seems impossible to have a user control being both cached and able to handle events. I must be missing something because that seems pretty shitty behavior to me.
If anyone knows what I'm'doing wrong, please tell.
In what scenario would you want to handle events and have the control cached? The only reason I see to handle events is either to change internal state, or change the display state. In either case, caching will remove that possibility.
Did you register the Control as a async postback control?
ScriptManager1.RegisterAsyncPostBackControl(CustomComponentDropDown);
Also, shouldn't
trigger.ControlID = CustomComponentDropDown.UniqueID.ToString();
Simply be
trigger.ControlID = CustomComponentDropDown.ID;
I have a user control that has multiple update panels
On Page Load, I load a child user control dynamically onto the PlaceHolder (I do this everytime and don't check for postback)
I want to be able to maintain the state of the changes that a user makes in the Child user control. (The child user control has html controls along with asp.net controls and other custom controls).
The child user control loses the state whenever there's a click on the Button A or B that causes the postback. The mode for UpdatePanels have been set to conditional.
In the OnPageLoad,
I load a child control to the PlaceHolderA
This child control has another user control with a lot of JS. A user can potentially make changes in the child control.
When they click on Button A which is a part of the parent control, the OnPageLoad causes the child control to reload causing it to lose the client side changes that a user has made.
I would like to prevent this from happening.
Here's the HTML structure of the ASPX page
<UpdatePanel1>
<UpdatePanelChild1>
<Button A>
<Button B>
</UpdatePanelChild1>
<UpdatePanelChild2>
<PlaceHolderA>
</UpdatePanelChild2>
When dynamically adding controls you need to re-add them everytime your page loads. I've had to tackle similar difficulties and I do this in two ways. Where dynamic fields are added o the fly I will actually add a hidden control to the page before the user clicks to fill it in or add it themselves. By creating this sort of placeholder the system has tim eto start handling viewstate correctly and this preserves the users changes. The second issue that I hear you mentioning is that there might be issues with chich update panel updates. It's fine to have them set to conditional bu tin your code-behind you can also trigger the updates in teh othe rpanels if you need to from code. It's just updatepanel#.update()
alternatively you can also wrap all the update panels in another panel but I advise against this as it wastes resources.
It looks like you're losing the ViewState for your dynamically-added child control.
This is because you're adding it too late in the page lifecycle: the ViewState is loaded before the Page.Load event.
Try adding your child control in Page.Init instead.
You could use a ScriptManager with a form runat server in your control, instead update panels.
This way you dont have the post backs.
Here a good reference: http://www.asp.net/Ajax/Documentation/Live/overview/ScriptManagerOverview.aspx
Greetings.
Josema.
http://www.learning-workshop.com
Blockquote
//Code in your Asp.Net code
<form runat="server" id="form1">
<asp:ScriptManager id="ScriptManager1" runat="server" >
<Services>
<asp:ServiceReference Path="/WebServices/MyService.asmx"/>
</Services>
</asp:ScriptManager>
</form>
<script language="javascript" type="text/javascript">
//call with namespace "WebSite" included
WebSite.WebServices.HelloWorld(EndHelloWorld);
function EndHelloWorld()
{
//do whatever
}
</script>
</form>
Blockquote
//Code in your webservice class
[ScriptService]
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public void HelloWorld()
{
return "Hello world";
}
}
From the script of my page i will do Ajax against my webservice, and the callback EndHelloWorld you could do whatever without losing state.
Hope it helps...
Kind Regards.
Josema.
It looks like you need to remove the nested UpdatePanels. In a structure like this:
<ParentUpdatePanel>
<ChildUpdatePanel1 />
<ChildUpdatePanel2 />
</ParentUpdatePanel />
ALL of the update panels will ALWAYS update, even if the child UpdatePanels are set to conditional, because the parent is actually the one that is updating. So, a postback event in one of the children will cause the parent to update.
Using that type of pattern is bad in general... if you need events from one UpdatePanel to cause updates in another, you should do this:
<asp:UpdatePanel ID="up1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button ID="buttonA" runat="server" />
<asp:Button ID="buttonB" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="up2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Placeholder ID="ph" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="buttonB" EventName="Click" />
</Triggers>
</asp:UpdatePanel>