I have a FormView that has an ItemTemplate, EditItemTemplate and InsertItemTemplate. I recently changed from VB to C# and my VB version worked perfectly. From what I can tell the only difference in the two versions is the datasource. My VB FormView used SqlDataSource, my C# is using EntityFramework. The DefaultMode is set to ReadOnly and when I click the Edit Command button I get a post back but the FormView doesn't change. If I click the button a second time I get the following error.
Line: 6
Error: Sys.WebForms.PageRequestManagerServerErrorException: 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.
I have
protected void FormView1_ModeChanging(object sender, FormViewModeEventArgs e)
{
}
because I was getting an error saying that I didn't have the ModeChanging event handled.
Here is my EditButton_Click()
protected void EditButton_Click(object sender, EventArgs e)
{ //I know that the FormView is supposed to automatically ChangeModes when the editbutton
//is clicked. However, I have tried with and without the below statement.
FormView1.ChangeMode(FormViewMode.Edit);
}
I fill my FormView with data using EntityFramework
//This is in my pages codeBehind
protected void ViewPartnerBtn_Click(object sender, EventArgs e)
{
List<FTP_GET_TESTING> dataList = ftpGetData.GetFTPSetup(FTPLookupDDL.SelectedValue);
FormView1.DataSource = ftpGetData.GetFTPSetup(FTPLookupDDL.SelectedValue);
FormView1.DataBind();
FormView1.ChangeMode(FormViewMode.ReadOnly);
}
//This is in my dataAccess class
public List<FTP_GET_TESTING> GetFTPSetup(String ftpLookupId)
{
using (Entities myEntities = new Entities())
{
var allFields = (from ftpGet in myEntities.FTP_GET_TESTING
where ftpGet.FTP_LOOKUP_ID == ftpLookupId
select ftpGet).ToList();
return allFields;
}
}
More info
My formview is contained within an update panel and I have tried a scriptManager in my master page, I have tried adding a scriptManagerProxy in my contentPage and I have also tried removing the scriptManager from the master and adding it directly to the contentPage.
Related
I need to add a UserControl dynamicaaly to a Panel on a page. The UserControl has a Repeater with the ID of ARepeater. I load and add the UC on Page_Init. I examine the value of ARepeater in Init, Load, and PreRender events of UC but ARepeater is always null.
protected Page_Init(object sender, EventArgs e)
{
var list = (NameList)Page.LoadControl(typeof(NameList), new object[1] { (int)Type });
Panel1.Controls.Add(list);
}
The NameList.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="NameList.ascx.cs" Inherits="MyCompant.Controls.BannersList" %>
<asp:Repeater ID="ARepeater" runat="server">
<ItemTemplate>
</ItemTemplate>
</asp:Repeater>
What I am doing wrong?
First of all, you do not need to be in Page_Init to work with dynamic controls. Page_Load is just fine. But in order to fill the Repeater you can create a property in the UserControl
public partial class WebUserControl1 : System.Web.UI.UserControl
{
public Repeater _ARepeater
{
get
{
return ARepeater;
}
set
{
ARepeater = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
Then you can access it from the page using the UserControl.
protected void Page_Load(object sender, EventArgs e)
{
var list = (WebUserControl1)LoadControl("~/WebUserControl1.ascx");
list.ID = "MyUserControl";
Panel1.Controls.Add(list);
list._ARepeater.DataSource = source;
list._ARepeater.DataBind();
}
Or use FindControl
var _ARepeater = (Repeater)Panel1.FindControl("MyUserControl").FindControl("ARepeater");
_ARepeater.DataSource = dt;
_ARepeater.DataBind();
You probably won't like this answer, but the overload for Page.LoadControl that allows for specifying the control's type and adding constructor arguments doesn't bind the ascx to the code-behind, and all associated child-controls will end up being null.
In the past, I've worked around this by adding another method for setting dependencies after constructing the user control, but it's not an ideal solution.
That said you aren't doing anything wrong. Binding will work properly if you use Page.LoadControl("~/path/to/mycontrol.ascx"), but you won't have constructor injection.
I believe the issue lies with the fact that the backing class doesn't actually have a relationship with the front-end page, except through the page directive that specifies it as the code-behind class. Nothing stops multiple different front-ends using the same class as it's code-behind, so loading by Type makes it either very difficult or outright impossible to determine what the correct ascx to bind would be.
Do web controls ever appear like you are changing their values but actually retain the previous value?
I created a pop-up modal for users to edit an item. When the user clicks edit on an item on the main page, the following sequence happens:
The item's ID is passed to the Page_Load event of the modal page, and is used to populate the page control's with the item's data.
The user changes a value in a control. Ex: Changes text in a TextBox contol.
The user clicks save, triggering the Click event which creates a DataTransferObject with the values in the textboxes, which will be stored.
However, on step 3, the control's new value (TextBox.Text) still holds the value that it orginially had, not the value the user put in.
Add.aspx:
<%# MasterType VirtualPath="../MasterPages/Popup.Master" %>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:TextBox ID="TextBoxDescription" runat="server"></asp:TextBox>
<telerik:RadButton ID="btnSave" runat="server" Text="Save" OnClick="btnSave_Click"/>
</asp:Content>
Add.aspx.cs
//Cannot access the new values here
protected void btnSave_Click(object sender, EventArgs e)
{
//This will print the new text on Create, but the old text on Edit
System.Diagnostics.Debug.WriteLine(TextBoxDescription.Text);
}
//works properly
protected void Page_Load(object sender, EventArgs e)
{
objIDParam = Convert.ToInt64(Request.QueryString["ObjectID"]);
editMode = (objIDParam != 0) ? true : false;
if(editMode)
PopulateFields(objID);
}
//works properly
private void PopulateFields(long objID)
{
MyObject obj = GetObjectByID(objID);
TextBoxDescription.Text = obj.Description;
}
It is worth noting that this popup page is used for both creating items AND editing items. Create works fine (i.e. The item isn't saved with all blanks, but rather the user input). Editing an item will properly pull all that data back in, and let the user edit the fields, however I can't access the changed values in my code.
You need to check for IsPostBack in the Page_Load method.
The Page_Load gets called before the btnSave_Click method, so the TextBoxDescription.Text is getting reset to obj.Description before the btn_Save method runs.
Try returning out of Page_Load if you're posting back:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
return;
objIDParam = Convert.ToInt64(Request.QueryString["ObjectID"]);
editMode = (objIDParam != 0) ? true : false;
if(editMode)
PopulateFields(objID);
}
Have a look at ASP.NET Page Life Cycle Overview for more info.
I have 2 ObjectDataSource's - 1 for the GridView and 1 for the FormView.
I enabled selection on the GridView and all is well; the page loads, you select a record, and the FormView populates with the record.
However, once the FormView is in Insert mode, when I select a record on the GridView, it is not changing back to display the record I selected.
Where could I handle this in the code, as I don't see how to access the "Enable Selection" on the GridView in code behind?
What I have tried
protected void grdSearchGroup_SelectedIndexChanged(object sender, EventArgs e)
{
formGroupInput.DefaultMode = FormViewMode.ReadOnly;
formGroupInput.DataBind();
}
protected void grdSearchGroup_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
formGroupInput.DefaultMode = FormViewMode.ReadOnly;
formGroupInput.DataBind();
}
I think the simplest way to solve your problem is to handle the GridView's SelectedIndexChanging method, and set the FormView back to read-only mode (that way you can see the records details in the FormView like you want).
protected void yourGridView_SelectedIndexChanging(Object sender, EventArgs e)
{
yourFormView.ChangeMode(FormViewMode.ReadOnly);
}
Note that you must call the FormView's ChangeMode method in order to update the mode. Just setting the DefaultMode property is not enough.
I am writing my own event handler for GridView in PageIndexChanging event, I didn't explicit set the DataSourceID for my GridView, here is my code:
Code for GridView data binding:
protected void DetailsView_DataBound (object sender, EventArgs e )
{
Customer cust = (Customer)DetailsView.DataItem;
this.GridView.DataSource = cust.Orders;
this.GridView.DataBind();
}
This part of the code allows me to show order details in GridView when data bound with DetailsView. Then I write my own GridView_PageIndexChanging event handler and DOES NOT work for me:
protected void GridView_PageIndexChanging(object sender, EventArgs e)
{
GridView.PageIndex = e.NewPageIndex();
GridView.DataBind();
}
If I click the next page number, the website shows nothing. But if I change GridView.DataBind() to DataBind() The paging works.
Anyone has any idea why the second Databind method works and what is the reason?
the second databind is DataBind(Page.DataBind) which refrence to current page binds all page controls and its child controls.
Have you set allowPaging="True" of gridview. if not then set it to true.
This question is about a very strange behavior of web controls. Consider the following please.
Scenario
I have a web control which is used to show some data. MyWebControl.ascx file is the following:
<%# Control ViewStateMode="Enabled"
Language="C#"
AutoEventWireup="true"
CodeFile="MyWebControl.ascx.cs"
Inherits="MyWebControl" %>
<div>
<asp:Label ID="MyLabel1" runat="server"></asp:Label>
<asp:Label ID="MyLabel2" runat="server"></asp:Label>
</div>
And code behind MyWebControl.ascx.cs is:
public partial class MyWebControl :
System.Web.UI.UserControl {
protected string str1;
protected string str2;
public string Str1 {
get { return this.str1; }
set { this.str1 = value; }
}
public string Str2 {
get { return this.str2; }
set { this.str2 = value; }
}
protected void Page_Load(object sender, EventArgs e) {
this.MyLabel1.Text = this.str1;
this.MyLabel2.Text = this.str2;
}
}
Well, I use this control inside a ListView of mine in an ordinary web form. This web form is called Default.aspx and, following, I am showing a slice of its code, only the one where the ListView resides in:
<%# Page Title="My page" Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%# Register TagPrefix="my" TagName="MyWC" Src="~/MyWebControl.ascx" %>
...
...
<div>
<asp:ListView ID="MyLV_ListView" runat="server"
EnableViewState="true"
OnPreRender="MyLV_ListView_PreRender"
OnItemDataBound="MyLV_ListView_ItemDataBound">
<ItemTemplate>
<my:MyWC ID="WC_MyWC" runat="server" />
</ItemTemplate>
</asp:ListView>
</div>
This web form code-behind Default.aspx.cs is:
public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
if (!this.IsPostBack) {
DAO d = new DAO(...); /* This object will contain some data */
/* Data are somehow paged, changing index, we have other data */
/* Please do not worry about paging, it works, problem is another */
d.PageIndex = 0;
this.ViewState["DAO"] = d; /* DAO is serializable */
this.ViewState["PageIndex"] = 0;
Data[] data = d.GetData(); /* Returns an array of objects representing my data */
/* Custom way of storing data in objects */
/* GetData use the PageIndex to get only a range of results */
this.MyLV_ListView.DataSource = data;
this.MyLV_ListView.DataBind();
}
}
protected void MyLV_ListView_ItemDataBound(object sender, ListViewItemEventArgs e) {
if (e.Item.ItemType == ListViewItemType.DataItem) {
((MyWebControl)e.Item.FindControl("WC_MyWC")).Str1 =
((Data)e.Item.DataItem).DataField1;
((MyWebControl)e.Item.FindControl("WC_MyWC")).Str2 =
((Data)e.Item.DataItem).DataField2;
}
}
protected void MyLV_ListView_PreRender(object sender, EventArgs e) {
if (this.IsPostBack)
this.MyLV_ListView.DataBind();
}
// A TreeView will cause the page to reload,
// this is the handler called when a tree node is
// selected, the node is used to change the page
// for showing data in my listview.
protected void MyLVPaging_TreeView_SelectedNodeChanged(object sender, EventArgs e) {
this.ViewState["PageIndex"] = int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value);
((DAO)this.ViewState["DAO"]).PageIndex = (int)this.ViewState["PageIndex"];
// After setting the new index, GetData will return another set of results
this.MyLV_ListView.DataSource = ((DAO)this.ViewState["DAO"]).GetData();
}
}
The problem
What is my problem???
Well, when the page loads for the first time I can see some data in the list view, so everything works.
When I select another page, I cause the page to reload and post back... my ListView will show the correct number of entries but with no data in it. The web control is placed as many times as the number of retrieved data records, but the web control has no data in it.
Debugging results
I conducted some debug sessions and this is what happens, please follow me, this is VERY IMPORTANT to understand I guess.
Page loads for the first time
1) Load page method is executed.
2) ListView's ItemDataBound event handler is executed. Well, given that I have three elements in the Data[] array in the DataSource, the handler is called three times. Inspecting values when proceeding debugging the method, I can see that ((Data)e.Item.DataItem).DataField1 and ((Data)e.Item.DataItem).DataField2 are the correct values retrieved from the bound data source in the ListView.
After the method is executed, the debugger cursor moves to MyWebControl.ascx.cs to the control's Page_Load method. I can see, inspecting variables, that this happens:
protected void Page_Load(object sender, EventArgs e) {
this.MyLabel1.Text = this.str1; // <-- this.str1 has the correct value loaded in the list view itemdatabound event handler.
this.MyLabel2.Text = this.str2; // <-- this.str2 has the correct value loaded in the list view itemdatabound event handler.
}
3) The ListView PreRender method is called.
4) The page shows and everyting is ok!
Page posts back after selecting a node in the TreeView
1) Load page method is executed but it does nothing.
2) MyLVPaging_TreeView_SelectedNodeChanged is executed. Here I can see that everything has the correct value:
protected void MyLVPaging_TreeView_SelectedNodeChanged(object sender, EventArgs e) {
this.ViewState["PageIndex"] =
int.Parse(this.MyLVPaging_TreeView.SelectedNode.Value); // <-- The new page
((DAO)this.ViewState["DAO"]).PageIndex =
(int)this.ViewState["PageIndex"]; // <-- Index saved
// After setting the new index, GetData will return another set of results
this.MyLV_ListView.DataSource =
((DAO)this.ViewState["DAO"]).GetData(); // <-- DataSource is changed
}
3) ListView's ItemDataBound event handler is executed. Well, here, debugging I can see the same as before, I mean, I can see that new values, new Data have been bound to the ListView, in fact I can inspect new values that are assigned to the template item.
Obviously, as before, after the method is executed, the debugger cursor moves to MyWebControl.ascx.cs to the control's Page_Load method.
HERE IS EVIL: I can see the following:
protected void Page_Load(object sender, EventArgs e) {
// Note: inspecting this.IsPostBack I get true!
this.MyLabel1.Text = this.str1; // <-- this.str1 is null and also this.MyLabel1.Text is null.
this.MyLabel2.Text = this.str2; // <-- this.str2 is null and also this.MyLabel1.Text is null. view itemdatabound event handler.
}
Well!!! IT LOSES STATE AND ALSO VALUES
PASSED BY THE LIST VIEW
HANDLER!!!!!!!!!
My question
What the hell is going on???
Notes
1) Please, do not focus too much on how I managed data binding on Load and PreRender events... I have a feeling this is not the error! I guess it is something related to the page lifecycle. However, if you think that this is important detail, let me know.
2) DAO and its function GetData() are a way to let you understand as quick as possible the scenario which is a little bit more articulated, but with the same exact structure I've shown here.
Thank you for your help.
From my comments:
Why don't you move the
this.MyLV_ListView.DataBind() from
PreRender to SelectedNodeChanged? And
why do you need the fields str1 and
str2 in your UserControl? The property
Str1 should get/set this.MyLabel1.Text
and the property Str2should get/set
this.MyLabel2.Text, because the
lables' Text are already stored in
ViewState.
Andry:
... so these kind of settings are not
to be made in the Load?
Me:
you don't need to wait for any event
to happen to set the label's text. The
properties should directly lead to the
corresponding Labels, hence your
fields str1 and str2 are redundant.
They will be disposed at the end of
the Page-Lifecycle as opposed to the
Text property of the Labels which are
stored in ViewState automatically
across postbacks.