"Failed to load view state" Error When dynamically loading user control - c#

I am having a User control [ascx] which is a radgrid. It also has a Edit column template which allow user to Insert/ change/update the values.
I am loading this user control on click of a button [Say EDIT] in aspx page.
When I click on EDIT button of aspx page the user control loads perfectly, but when I click on the Add New Record of user control I get this error message.
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save
viewstate during the previous request. For example, when adding
controls dynamically, the controls added during a post-back must match
the type and position of the controls added during the initial
request.
//code of user control -ascx
<telerik:RadGrid AllowAutomaticDeletes="True"
AllowAutomaticInserts="False" AllowAutomaticUpdates="False"
Height="410px" ID="rgrd1" runat="server" AutoGenerateColumns="False"
OnUpdateCommand="rgrd1_UpdateCommand"
OnInsertCommand="rgrd1_InsertCommand" OnNeedDataSource="rgrd1_NeedDataSource" GridLines="None">
<MasterTableView CommandItemDisplay="top" CommandItemStyle-Wrap="False" CommandItemStyle-HorizontalAlign="Left"
DataKeyNames="Type">
<Columns>
<telerik:GridEditCommandColumn UniqueName="EditColumn" HeaderStyle-HorizontalAlign="left"
HeaderText="Edit" ButtonType="ImageButton">
</telerik:GridEditCommandColumn>
<telerik:GridTemplateColumn DataField="Type" HeaderStyle-HorizontalAlign="left"
HeaderText="Type" UniqueName="Type">
<ItemTemplate>
<asp:Label ID="TypeLabel" runat="server" Text='<%# Eval("Type") %>'></asp:Label>
</ItemTemplate>
</telerik:GridTemplateColumn>
</Columns>
<EditFormSettings EditFormType="Template">
<EditColumn FilterControlAltText="Filter EditCommandColumn1 column" UniqueName="EditCommandColumn1">
</EditColumn>
<FormTemplate>
<table>
<td>
<telerik:RadTextBox ID="txtType" Width="50" runat="server" Text='<%# Eval("Type") %>'>
</telerik:RadTextBox>
</td>
</tr>
</table>
</FormTemplate>
</EditFormSettings>
</MasterTableView>
<HeaderStyle HorizontalAlign="Center" />
</telerik:RadGrid>
.....................................
Code of my aspx page - in which i am loading the above usercontrol in Radwindow
On click of EDIT button - below code i have written-
RadWindow window = new RadWindow();
window.Height = Unit.Pixel(500);
window.Width = Unit.Pixel(500);
window.VisibleOnPageLoad = true;
UserControl uc = (UserControl)Page.LoadControl("../../Controls/TypeUserControl.ascx");
uc.EnableViewState = false;
window.ContentContainer.Controls.Add(uc);
pnl.Controls.Add(window);
When I click on Add New Record in usercontrol it throws the exception "Failed to load view state:"
I have aspx page on which this user control is loaded is being inherited by my BasePage.
Exception is coming in OnPreRender of base page
protected override void OnPreRender(EventArgs e)
{
try
{
base.OnPreRender(e);
}
}
User control - code behing
public partial class TypeUserControl : System.Web.UI.UserControl
{
protected void rgrd1Types_NeedDataSource(object source, GridNeedDataSourceEventArgs e)
{
try
{
//dbase call
}
catch (Exception ex)
{
SetValidationMessage(ex.Message.ToString());
}
}
protected void rgrd1_InsertCommand(object source, GridCommandEventArgs e)
{
try
{
//dbase call
}
catch (Exception ex)
{
SetValidationMessage(ex.Message.ToString());
}
}

I don't know if this is the issue, but your HTML is not correct in your Form Template
<table>
<td>
<telerik:RadTextBox ID="txtType" Width="50" runat="server" Text='<%# Eval("Type") %>'>
</telerik:RadTextBox>
</td>
</tr>
</table>
you are missing the opening <tr> tag. this could have something to do with the issue.
you should double check all your code to make sure that it is correct.
--
I am also guessing that you should remove this line of code from the Edit button's OnClick() event
uc.EnableViewState = false;

You have to recreate the control on postback as you add it dynamically.
Recreate or Add the control in the Init_page Eventhandler, there you can check the type of event or control, that caused the postback, to know that you should recreate this control.
Can you post the code-behind file.
EDIT:
It's a long time ago, when I did this. But here is a working example.
I think there is a better way.
Check the keys collection, which button caused the postback, if it is a certain button in your ascx control then readd your control to the page or whereever you put it, but it must be the same place on postback, otherwise you will get an error, I think.
protected override void OnInit(EventArgs e) { base.OnInit(e);
if (this.Page.IsPostBack) {
var x = base.DeterminePostBackMode();
if (x.Keys.Get(3).Contains("btnInControl"))
{
Control ctrl = Page.LoadControl("WebUserControl1.ascx");
this.Page.Form.Controls.Add(ctrl);
}
}
}

It has been a year since you posted this issue but just in case someone still facing this: here is the main root of this type of error. I have been struggling big time with it.
The easiest way to fix your bug is to set to the control you add dynamically :
EnableViewState = false
If you need the Viewstate, the other options you have are to add the control you add dynamically onInit, or recreate it on every Postback.
Hope it helps.
See Funkylife's comment for more information.

Related

ASP.NET DataGrid is empty

I have a ASP.NET datagrid which is on a user control. I have a main page which adds the user control ( sometimes multiple copies of the user control ) and restores them when a post back occurs.
The dataGrid has insert / edit / delete links. I can add multiple copies of the user control to the page and the insert / edit delete functionality works perfectly for each separate control.
Yesterday I added some property binding to the main page to which are unrelated to the user control using the format Text='<%# DocumentTitle %>'. Initially I couldn't get this to work until I added Page.DataBind(); to the main page's Page_Load method. At this point the property binding started working correctly but then I noticed the insert functionality had stopped working in the datagrid within each user control....I debugged and found that when the following line executes it finds the text fields in the controls within the dataGrid to be empty or "":
eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;
If I remove the page.DataBind() method from the main page then the property binding stops working but the dataGrid(s) in the userControl start working.
My question is two fold i) Why does the seemingly unrelated change effect the dataGrid and ii) what do I do to get this working?
I've added the relevant sections of my code below...or at least what I think are the relevant sections.
Default.aspx
<div class="general">
<asp:TextBox Width="488" runat="server" placeholder="Document Title" Text='<%# DocumentTitle %>'></asp:TextBox>
</div>
Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Create an empty user control for the first requirements section.
EmployeeSectionUserControl myUserControl1 = (EmployeeSectionUserControl )LoadControl("~/EmployeeSectionUserControl .ascx");
// Add it to the panel control holding all the user controls.
MainPanel.Controls.Add(myUserControl1);
DocumentTitle = "I am the default document title and I'm bound.";
}
else
{
// Do nothing
}
Page.DataBind();
}
EmployeeSectionUserControl.ascx
<asp:GridView ID="gvEG" runat="server" AutoGenerateColumns="False" CssClass="grid"
AlternatingRowStyle-CssClass="gridAltRow" RowStyle-CssClass="gridRow" ShowFooter="True"
EditRowStyle-CssClass="gridEditRow" FooterStyle-CssClass="gridFooterRow" OnRowCancelingEdit="gvEG_RowCancelingEdit"
OnRowCommand="gvEG_RowCommand" OnRowDataBound="gvEG_RowDataBound" OnRowDeleting="gvEG_RowDeleting"
OnRowEditing="gvEG_RowEditing" OnRowUpdating="gvEG_RowUpdating" DataKeyNames="Id" ShowHeaderWhenEmpty="true">
<Columns>
<asp:TemplateField HeaderText="Id" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="50px">
<ItemTemplate>
<%# Eval("Id")%>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Ref" HeaderStyle-HorizontalAlign="Left" ControlStyle-Width="90px">
<EditItemTemplate>
<asp:TextBox ID="txtEmployeeName" runat="server" Text='<%# Bind("Ref") %>'
Width="90px"></asp:TextBox>
</EditItemTemplate>
<FooterTemplate>
<asp:TextBox ID="txtEmployeeName" runat="server" Width="90px"></asp:TextBox>
</FooterTemplate>
EmployeeSectionUserControl.ascx.cs
protected void gvEG_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.Equals("Insert"))
{
employeeInfo eInfo = new employeeInfo();
eInfo.Id = 999;// Convert.ToInt32(((TextBox)gvEG.FooterRow.FindControl("Id")).Text);
// If we're inserting from the EmptyDataTemplate( ie an empty table ) of the gridview then we need to retreive the data differently.
// So we perform a check on the gridView FooterRow and if it's null then we can assume it's an empty table.
if (gvEG.FooterRow == null)
{
TextBox referenceTxtBox = (((Control)e.CommandSource).NamingContainer).FindControl("txtEmployeeName") as TextBox;
eInfo.Ref = referenceTxtBox.Text;
}
else
{
eInfo.Ref = ((TextBox)gvEG.FooterRow.FindControl("txtEmployeeName")).Text;
eInfo.Need =
}
// Store Update and Re-bind data to grid.
}
}
Page.DataBind() calls DataBind on it's children, so it updates DocumentTitle in the text box but it also DataBinds your grid. I didn't see a DataSource set in your grid, like an EntityDataSource, so I am assuming you are doing the smart retrieving (and preparation) of the data yourself in code and set the DataSource yourself:
gvEg.DataSource = someCollection;
gvEg.DataBind();
On the get your are loading the user-control and probably call this DataBind with specifying the DataSource. It binds and then you call Page.DataBind() which probably also triggers another DataBind for gvEg but since DataSource is set it shows the same.
On the post back you shouldn't do a DataBind() before handling events. Your call of Page.DataBind() does that. It triggers a DataBind() without a DataSource. Then the rowCommand comes and checks for the TextBox in the Footer which is cleared due to a DataBind with no elements.
What you should do is:
You shouldn't use Page.DataBind(). If you do so, you need todo it at a moment when all DataSources are set correctly and it shouldn't be kicked of during a post back. In general, I would not recommend using it because it makes it more complex and it's probably only helping a bit if you haven't set up your application correctly.
In your case it's definitely not necessary. Your textBox is a server control that's not part of any binding (GridView, Repeater, ListView). So your textBox is immediately available in your code behind.
So you should:
Give the textBox an ID you can use like txtDocumentTitle
<asp:TextBox Width="488" ID="txtDocumentTitle" runat="server" placeholder="Document Title"></asp:TextBox>
Replace setting DocumentTitle (unless you need it for something else too) with:
txtDocumentTitle.Text = "I am the default document title and I'm bound.";
Remove Page.DataBind();
So access server controls you have access immediately since they are also properties in your page or control.

Breakpoint not hitting on ItemDataBound function

I have a grid control called RadGrid1 and with a breakpoint in RadGrid1_ItemDataBound, but when I run my aspx application, the breakpoint is not being triggered.
my code is:
<telerik:RadGrid ID="RadGrid1" runat="server" Width="980px" CssClass="GridDisplay"
AllowAutomaticDeletes="false" AllowAutomaticInserts="false" AllowAutomaticUpdates="true" AllowPaging="true"
AutoGenerateColumns="False" AutoGenerateDeleteColumn="false" AutoGenerateEditColumn="false" ItemStyle-Height="20px"
ClientSettings-ActiveRowIndex="true" EnableViewState = "false" OnDeleteCommand = "RadGrid1_OnDelete"
OnItemCreated = "RadGrid1_ItemCreated" OnItemDatabound = "RadGrid1_ItemDatabound" OnNeedDataSource = "RadGrid1_NeedDataSource">
<telerik:GridTemplateColumn DataField="Confirmed" HeaderText="Confirmed" UniqueName="Confirmed" Visible="true">
<ItemTemplate>
<asp:CheckBox ID="chkVerified" runat="server" AutoPostBack="true"
Checked='<%# bool.Parse(Eval("Verified").ToString()) %>'
Enabled='<%# !!Convert.ToBoolean(Convert.ToInt32(Eval("Verified").ToString())) %>'
ToolTip='<%# Eval("NoConfirmDesc").ToString() %>'
/>
</ItemTemplate>
</telerik:GridTemplateColumn>
aspx.cs
private void RadGrid1_ItemDataBound(object sender, Telerik.Web.UI.GridItemEventArgs e)
{
if (e.Item is GridDataItem)
{ }
}
In aspx, the handler for Databound event is called RadGrid1_ItemDatabound
OnItemDatabound = "RadGrid1_ItemDatabound"
but in code behind, your method is spelled with capital B in databound
void RadGrid1_ItemDataBound
Make sure you place the breakpoint inside the right method.
Could you make sure AutoEventWireup="true" for the page?
<%# Page ... AutoEventWireup="true" %>
In addition, make sure that there are not spaces between them OnItemDatabound="RadGrid1_ItemDatabound"
One thing I notice in your code is you want to use OnNeedDataSource to bind Data if you use RadGrid.
OnNeedDataSource="RadGrid1_NeedDataSource"
maybe you forgot to register or are not correctly registering the OnItemDataBound Event
Or maybe you are not databinding the control?
RadGrid1.DataSource= mydatasource;
RadGrid1.DataBind();
As last possibility maybe iis express and visualstudio debugger are not working correclty
I suggest to kill iisexpress process and then rebuild the solution then try again

PostBackTrigger on multiple LinkButtons in an update panel

I have a search form in an updatePanel which retrieves a list of users in a grid in the same UpdatePanel. The name of each user is a commandLink. I want to make the commandLinks as PostBackTriggers.
But when I do it I get an error at the pageLoad time that the controlId does not exist and its true because the grid of users does not render at the load time but through an ajax call.
Any ideas on how can I make the multiple command buttons in a grid retrieved through ajax call as post back triggers?
When adding the items to the grid, within the ItemDataBound event handler, you should register the postback for each specific control (the static identifiers in your HTML declarations are essentially placeholders - not all things repeated in the grid can actually have the same ID). You do this using the ScriptManager.RegisterAsyncPostBackControl method:
The RegisterAsyncPostBackControl method enables you to register Web
server controls as triggers so that they perform an asynchronous
postback instead of a synchronous postback. When the
ChildrenAsTriggers property of an UpdatePanel control is set to true
(which is the default), postback controls inside the UpdatePanel
control are automatically registered as asynchronous postback
controls.
As stated above, using ChildrenAsTriggers is a possibility, too, but this is commonly set to false for more stringent management.
I have found the solution. Here is the code on asp
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:TextBox ID="txtFirstName" runat="server"></asp:TextBox>
<asp:Button ID="btnSearch" runat="server" OnClick="btnSearch_Click" Text="Search" />
<asp:GridView ID="gvSearchResult" runat="server" OnRowCommand="gvSearchResult_RowCommand"
OnRowDataBound="gvSearchResult_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:LinkButton ID="lnkbtnDetail" runat="server" CommandArgument='<%# Bind("CNIC") %>' CommandName="Detail">
<asp:Label ID="lblName" Text='<%# Bind("Employee_Name") %>' runat="server</asp:Label>
</asp:LinkButton>
</ItemTemplate>
<ItemStyle HorizontalAlign="Left" VerticalAlign="Middle"Height="25px"Width="30%" />
</asp:TemplateField>
</Columns>
</asp:GridView>
Ihad to place OnRowDataBound="gvSearchResult_RowDataBound" on gridView and that function looks like below. So I had to register the iterative control in Scriptmanager as PostBackControl in RowDataBound event of GridView.
protected void gvSearchResult_RowDataBound(object sender, GridViewRowEventArgs e)
{
try
{
if ((e.Row.RowType == DataControlRowType.DataRow))
{
LinkButton lnkbtnDetail = (LinkButton)e.Row.FindControl("lnkbtnDetail");
ScriptManager.GetCurrent(this).RegisterPostBackControl(lnkbtnDetail);
}
}
catch (Exception ex)
{
}
}

How to get selected items of Listbox control?

I am developing an application in ASP.NET & c#. I have a Grid view in my page. In that I have a Listbox control and by default Enabled property set by false. I am trying to enable & disable that control from javascript / jQuery on Checkbox control.
My ASP Code:
<asp:GridView ID="gvWhom" runat="server" AutoGenerateColumns="False" DataSourceID="odsWhom"
GridLines="None" Width="100%" OnRowDataBound="gvWhom_RowDataBound">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
</HeaderTemplate>
<ItemTemplate>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr style="height: 25px;">
<td width="20%">
<asp:CheckBox ID="chkCriteria" runat="server" Text='<%#Eval("TargetType") %>' />
</td>
<td width="80%">
<asp:ListBox ID="lbCriteria" runat="server" CssClass="ddl" Width="150px" Height="50px"
Enabled="false" SelectionMode="Multiple"></asp:ListBox>
</td>
</table>
</ItemTemplate>
<HeaderStyle Height="2px" />
</asp:TemplateField>
</Columns>
</asp:GridView>
Javascript Code:
function disableDropDown(chkCriteria, lbCriteria) {
if (document.getElementById(chkCriteria).checked) {
document.getElementById(lbCriteria).removeAttribute('disabled');
}else{
document.getElementById(lbCriteria).value = -1;
document.getElementById(lbCriteria).disabled = true;
}
return true;
}
C# Code:
protected void gvWhom_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
ListBox lbCriteria = (ListBox)e.Row.FindControl("lbCriteria");
CheckBox chkCriteria = (CheckBox)e.Row.FindControl("chkCriteria");
chkCriteria.Attributes.Add("onchange", "javascript:return disableDropDown('" + chkCriteria.ClientID + "', '" + lbCriteria.ClientID + "')");
}
}
Using above code I am able to enable / disable the Listbox control. But when I enable the control and select multiple items and submitting the form I am not able to find selected items of Listbox.
How can I fetch selected items of Listbox? or Is there any other way to enable - disable the listbox control and get the selected items in c# code?
This is mostly a guess, but it's worth a try...
You're disabling the control on the server-side here:
<asp:ListBox ID="lbCriteria" runat="server" CssClass="ddl" Width="150px" Height="50px"
Enabled="false" SelectionMode="Multiple"></asp:ListBox>
That Enabled="false" may be indicating to ASP.NET that it doesn't need to track this control, that changes won't be made to it. That might be why it's not getting the data back when you post back to the server.
Let's try keeping the control enabled from the server's (ASP.NET's) perspective, and maintaining the enabling/disabling in the UI entirely on the client's (JavaScript's) side. Essentially removing ASP.NET's built-in framework from making decisions for you regarding what data to track.
Start by enabling the control in the server-side control markup:
<asp:ListBox ID="lbCriteria" runat="server" CssClass="ddl" Width="150px" Height="50px"
SelectionMode="Multiple"></asp:ListBox>
The rest is handled by JavaScript. You already have some JavaScript code which you say enables/disabled the control on the client-side for you, correct? So all you need to do now is call that same JavaScript for every instance of the control when the page first loads in the browser to disable the controls client-side. This is the part you want:
document.getElementById(lbCriteria).value = -1;
document.getElementById(lbCriteria).disabled = true;
Now, it looks like you're binding your JavaScript events from the server-side code, which is where I won't be able to help as much because that method isn't particularly intuitive to me. (It's mixing JavaScript and C#, which feels a bit backwards.) So I'm not entirely sure the approach you'd take there.
Essentially you want to invoke those two lines of JavaScript for every instance of the control, and you want it to happen as soon as the page loads in the browser.
In jQuery I'd do something like this:
$(function () {
$('select.ddl').attr('disabled', 'disabled');
});
This would run when the DOM is loaded and would add the disabled attribute (with a value of "disabled" to every select with the class ddl.

Web User Control postback Issues

I am new to ASP.net thing, and i have some question regarding postback.
I have a Senario like this:
1) I have a grid on web with a panel inside.
2) I "Insert" the panel with a Web User Control by calling this
Control ctlControl;
ctlControl = LoadControl("~/UserControls/ChequeCreation.ascx");
pnlTransaction.Controls.Add(ctlControl);
3)The Web User Control providing two button. One is "update" and one is "reset".
Problem is like here:
What i wanted to achieve is when press the "update" button, it will update something back to my DB? But seem after i press the button "Update" or "Reset". The web user control is gone or missing. For my guest is because of the postback issues? Is that correct?
I tried if(!postback) still its doesn't work.
How am i going to overcome this? I already scratching my head about a day?
Thanks you so much.
Regards
LiangCk:
PS:Sorry for my english level, and please dont hesitate to voice out my error or mistake.
well you can convert any of your data columns to template column and then drag and drop your web user control to it
this will result in something like the following code check where "uc1:webUserControle1" is located in the code
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" DataSourceID="SqlDB">
<Columns>
<asp:TemplateField HeaderText="ID" SortExpression="ID">
<EditItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("ID") %>'></asp:Label>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("ID") %>'></asp:Label>
<uc1:webUserControle1 ID="WebUserControle1_1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
</Columns>
</asp:GridView>
if you are using AJAX, try add updatepanel on your UCT design page
ASP.NET will not preserve a dynamically added user control between postbacks. This is why it is dissapearing. You will need to add the control each time the page is created. However you will need to add it when the control tree is being initialized and restore the original control ID if you want your events to fire. These links provide a full explanation https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx and http://avinashsing.sunkur.com/2011/02/24/dynamic-controls-viewstate-and-postback/
You have to Every Time Reload the user control on Page_Init or
Page_Load. Then you can get the Button Click Event and After tha User
Control will not lost.
private void LoadUserControl(){
string controlPath = LastLoadedControl;
if (!string.IsNullOrEmpty(controlPath)) {
PlaceHolder1.Controls.Clear();
UserControl uc = (UserControl)LoadControl(controlPath);
PlaceHolder1.Controls.Add(uc);
}
}
protected void Page_Load(object sender, EventArgs e) {
LoadUserControl();
}

Categories

Resources