Why is my UserControl's ViewState partially saved? - asp.net

I have a user control that makes substantial use of this.ViewState["Key"] = SomeValue. Most of it is loaded from my Page_Init():
protected void Page_Init(object sender, EventArgs e)
{
if(!IsPostBack)
{
ViewState["Blahblah"] = LoadSomeValue();
}
}
The rest are set at various points.
But for some reason it's unavailable on subsequent postbacks. I overrode SaveViewState() to check, and only like three of them are saved!
protected override object SaveViewState()
{
List<object> viewStateObjectsBefore = ViewState.OfType<object>().ToList();
object ret = base.SaveViewState();
List<object> viewStateObjectsAfter = ViewState.OfType<object>().ToList();
GC.KeepAlive(viewStateObjectsBefore);
GC.KeepAlive(viewStateObjectsAfter);
GC.KeepAlive(ret);
return ret;
}
Both viewStateObjectsBefore and viewStateObjectsAfter contain 10 key/value pairs, but ret only contains three!
Added: Moving the initializations to Page_Load() is not an easily available option, because the initializations must be done before the parent's Page_Load() executes.

Adding a call to SetDirty() at the end of my Page_Init() solved the problem:
protected void Page_Init(object sender, EventArgs e)
{
if(!IsPostBack)
{
ViewState["Blahblah"] = LoadSomeValue();
//Looks like the ViewState is not yet "tracking" changes before Page_Load.
//The items have to be marked as "dirty" manually so they'll be included by SaveViewState().
ViewState.SetDirty(true);
}
}

Related

How to maintain class after button click on page

I have a page in ASP .NET where when I access it, programmatically I set a value in the TextBox. When I click on the Button, I would like to update that value, but it gives me error:
Object not defined
Here is my code:
public partial class InsertValues : System.Web.UI.Page
{
DataProvider dataProvider = new DataProvider(); // This class contains all the querys I need to pull data
public MyValuesClass myValues; // This is my class where I get the data from my DB
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
startMyPage(); // Function that gets the values from the DataBase and sets my TextBox with the values.
}
else
{
}
}
private void startMyPage()
{
myValues = dataProvider.getValuesFromDB(); // Function that gets the values from a query and put them in my class, the values are. String "Banana" and Bool isNew = True
if (!myValues.isNew) //
{
txtFood.Text = myValues.food
}
else
{
myValues= new myValues();
myValues.isNew = true;
}
}
protected void btnSave_Click(object sender, EventArgs e)
{
if (myValues.isNew) // Object not defined.
{
dataProvider.addMyValues(myValues); // It Inserts into my DB
}
else
{
dataProvider.editMyValues(myValues); // It Updates into my DB
}
}
}
Basically, after I click on my "btnSave" the class myValues becomes null, and I get the error Object not defined, is there a way to maintain the class Values?
You need to refetch your myValues object on PostBack.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
startMyPage();
}
else
{
myValues = dataProvider.getValuesFromDB();
}
}
Only data that's stored in the ViewState or equivalent persistence mechanism will be kept between the initial page load and post backs, which is why values of your webforms page controls are persisted, but your code behind property isn't.
You can store things manually in the ViewState like this: ViewState["someKey"] = someObject;, but someObject has to be serializable. It looks like myValues is an ORM object, so it probably isn't serializable.
All Variables are re-initiated at every post back. you better store your class public MyValuesClass myValues in session or viewstate.

How to update CheckBoxes on the client side after making changes on the server side?

I have a DropDownList and a CheckBox on my web form. After the DropDownList is clicked and this event is posted back to the server. DropDownList_SelectedIndexChanged event is called on the server side. Inside that event handler, I have CheckBox.Checked = true, But I couldn't make the page on the client side to reflect this change (CheckBox.Checked = true). How do I achieve this? Or am I in the wrong direction to use the DropDownList's event handler to update the CheckBox because the page firstly reloads and then DropDownList_SelectedIndexChanged is called?
Page load method:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
this.DropDownList1.Items.Clear();
AddItemsToDropDownList();
}
}
DropDownList selected index changed event handler:
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
var selected = this.DropDownList1.SelectedItem.Text;
CheckBox checkBox = GetCheckBoxToBeSetByText(selected);
checkBox.Checked = true;
}
OK. Found the issue. Actually there is nothing wrong with the code in my original post. But to make a smallest sample when I posted, I removed some "extra" code. The below is the "complete" code (OK, fine, I still removed some code). As you can see, I put the CheckBox into a static Dictionary. Each time the SelectedIndexChanged event handler is called, it's modifying the CheckBox in that static Dictionary, which means it's modifying the CheckBox object created from the last session? (still not clear here) Looks like each time when a postback message is received, a new set of CheckBox objects are created. Bear with me if this is known to everybody here already because I only have two days of experience on this web development thing up to today.
private static Dictionary<Environment, CheckBox> EnvironmentsCheckBoxes;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
EnvironmentsCheckBoxes = new Dictionary<Environment,CheckBox>();
EnvironmentsCheckBoxes.Add(Environment.Dev1, this.Dev1_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.Dev2, this.Dev2_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.QA, this.QA_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.QA2, this.QA2_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.Demo, this.Demo_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.Prod, this.Prod_CheckBox);
EnvironmentsCheckBoxes.Add(Environment.UAT, this.UAT_CheckBox);
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
var selected = this.DropDownList1.SelectedItem.Text;
if (selected == "Dev1")
{
EnvironmentsCheckBoxes[Environment.Dev1].Checked = true;
}
else if (selected == "Dev2")
{
...
}
...
}

Collection was modified enumeration operation may not execute in datalist

I am getting error when i try to fire event after clicking button which is outside datalist.
Error shows in for each statement :
Collection was modified enumeration operation may not execute.
protected void btnSaveGrid_Click(object sender, EventArgs e)
{
foreach (DataListItem item in dlPl.Items)
{
CommandEventArgs commandArgs = new CommandEventArgs("SaveGrid", btnSaveGrid);
DataListCommandEventArgs repeaterArgs = new DataListCommandEventArgs(item,btnSaveGrid, commandArgs);
dlPl_ItemCommand(btnSaveGrid, repeaterArgs);
}
protected void dlPl_ItemCommand(object source, DataListCommandEventArgs e)
{
if (e.CommandName == "SaveGrid")
{
//Some work
}
}
can anyone help me?
You may not modify the collection while you are enumerating it. dlPl_ItemCommand modifies dlPl.Items, which is not allowed.If you move DataBind outside the loop, it should work.

How to know the previous event handled in asp.net

on page load i have shown data from database onto a gridview(with edit and delete option). I also have a search button on the page. when i click on search the searched data should be visible in the gridview, which is working fine. But when i click on delete link after search it does not take the searched row. The page postsback after clicking on delete. I need to check the event performed prior to event performed on gridview. How to do that?? I hope that the issue is clear.. Any help is appreciated. Thanks.
Page_Load occurs before RowCommand, are you only binding grid if(!IsPostBack) ?
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
BindGrid();
}
}
protected void SearchButton_Click(object sender, EventArgs e)
{
BindGrid(searchText.Text);
}
protected void GridView_RowCommand(object sender, GridViewRowEventArgs e)
{
switch(e.CommandName)
{
case "Delete":
DeleteRow(e.Row.CommandArgument);
break;
}
}
private void BindGrid()
{
//GridView binding business logic.
}
private void BindGrid(String searchTerm)
{
//GridView binding logic with searchTerm.
}
private void DeleteRow(String commandArg)
{
//Convert command arg to ID or whatever and delete data.
}

How can I prevent the LinqDataSource Where clause from resetting on postback?

I'm trying to set the where clause on a LinqDataSource object bound to a GridView programmatically on a button click, but when the GridView rebinds data (for instance, when the user sorts) the Where clause resets back to the empty string. Is there a way to prevent this, or is there a better way to filter my results?
Perhaps you just add a ViewState property into your page/user control and then retrieve it on all post back?
public string MyLinqSourceWhere
{
get { return (string)this.ViewState["MyLinqSourceWhere"]; }
set { this.ViewState["MyLinqSourceWhere"] = value; }
}
public void Page_Load(object sender, EventArgs e)
{
this.myLinqSource.Where = this.MyLinqSourceWhere;
}
public void Button1_Click(object sender, EventArgs e)
{
this.MyLinqSourceWhere = " .... ";
this.myLinqSource.Where = this.MyLinqSourceWhere;
}
If that doesn't work, then perhaps bind on the LinqDataSource.Selecting event the fetch property from the viewstate to your where clause?? It all depends

Resources