I've seen this problem a lot, and it's usually because the ViewState variables are being evaluated too early in the page lifecycle, or that EnableViewState is false, but I've checked for both of these and they are as I'd expect them to be.
My code:
public Int32 MyNumber
{
get
{
if (ViewState["MyNumber"] != null)
{
return (Int32)ViewState["MyNumber"];
}
return 0;
}
set
{
ViewState["MyNumber"] = value;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!this.IsPostBack)
{
MyNumber = 23;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var numberValue = MyNumber;
}
When OnPreRender is first called, numberValue is 23. Every subsequent call thereafter it's 0. Every time there's a postback it appears to get reset.
Question
How do I get the value to persist after a postback?
What I've Tried
Bringing the value assignment outside of the check for a postback, but then that defeats the purpose of using ViewState in the first place.
I was unaware there was also a ViewStateMode that would cause this behaviour if set to Disabled, which it was (on the master page).
I've now set that to Enabled on my control, and my ViewState values persist as I'd hope.
actually you have a missing order in your code block excaution and that makes the value reset by zero everytime between post packs :) ... in the onload Method you wrote the base.onload() method before your code block and that lead the Viewstate to be reset to 0 .
Please fellow that code correction:
public Int32 MyNumber
{
get
{
if (ViewState["MyNumber"] != null)
{
return (Int32)ViewState["MyNumber"];
}
return 0;
}
set
{
ViewState["MyNumber"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(MyNumber.ToString()); // Result now is 23 :)
}
protected override void OnLoad(EventArgs e)
{
// I replaced the order of the code here to get the value of the Viewstate in MyNumber property ..
if (!this.IsPostBack)
{
MyNumber = 23;
}
base.OnLoad(e);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var numberValue = MyNumber;
}
Good Luck :).
Related
Goal: Keep value of int (professorIndex) reachable when I get to the button click method (btnUpdateAvailability_Click())
Problem: The value gets set correctly initially, then somehow goes to 0
What ive tried: Starting variable at class level. Getting rid of any other references to it, including commenting out where it was set to 0
What am I missing?
C#:
public partial class SiteMaster : MasterPage
{
private int professorIndex;
protected void Page_Load(object sender, EventArgs e) {
//some stuff
}
protected void cbUpdateAvailability_Click(object sender, EventArgs e)
{
CheckBox cbSender = (CheckBox)sender;
professorIndex = getProfessorIndexCB(cbSender.ClientID);
//at this point, professorIndex is 1, which is what I want/expect
}
public int getProviderIndexCB(string cbSender)
{
//professorIndex = 0;
switch (cbSender)
{
case "chkOnOff1":
professorIndex = 0;
break;
case "chkOnOff2":
professorIndex = 1; //This is the one that is triggered
break;
}
return professorIndex;
}
protected void btnUpdateAvailability_Click(object sender, EventArgs e)
{
//at this point, professorIndex is 0, no clue why. It should be one
}
Below a simple demo to store a value you want to persist in a Session and get it back on PostBack.
public int professorIndex = 0;
protected void Page_Load(object sender, EventArgs e)
{
//check for postback
if (!IsPostBack)
{
//set the index
professorIndex = 10;
//store the index in a session
Session["professorIndex"] = professorIndex;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//check if the session exists
if (Session["professorIndex"] != null)
{
//cast the session back to an int
professorIndex = (int)Session["professorIndex"];
}
//show result
Label1.Text = $"The professor index is {professorIndex}.";
}
I have a composite control like:
class MyControl : CompositeControl {
private Control _control1;
private Control _control2;
public bool RenderControl2 { get; set; }
/* Constructor to initialize controls*/
protected override void CreateChildControls(){
if(RenderControl2){
Controls.Add(_control2);
}else{
Controls.Add(_control1);
}
}
}
This works fine in scenarios where the value of RenderControl2 is set during Page_Init().
protected void Page_Init(object sender, EventArgs e){
if (!Page.IsPostBack){
myControl.RenderControl2 = MyMagicFucntion();
}
/* Works also when in Postback, but not required since the control keeps it state and only need to change state in the scenario below.*/
}
However, now we would like to set the value as a result of an event
protected void otherDropDow_SelectedIndexChanged(object sender, EventArgs e) {
myControl.RenderControl2 = otherDropDown.SelectedValue == "My Magic String";
}
This does not work since the control already executed CreateChildControls by the time the event fired. (Well, it does work during the next postback... :( )
I have tried to move the logic to the OnDataBinding event of the control. But this seems to have no impact on how the control actually show on the page.
/* DOES NOT RESOLVE THE ISSUE */
protected override void OnDataBinding(EventArgs e){
base.OnDataBinding(e);
/* _renderControl2HasChanged is set when RenderControl2 changes value
*/
if(_renderControl2HasChanged)
if(RenderControl2){
Controls.Remove(_control1);
Controls.Add(_control2);
}else{
Controls.Remove(_control2);
Controls.Add(_control1);
}
}
Instead of making the decision which control to display in CreateChildControls, you could evaluate the flag in OnPreRender and only change the visibility of the child controls, e.g.:
protected override void CreateChildControls()
{
Controls.Add(_control1);
Controls.Add(_control2);
}
protected override void OnPreRender(EventArgs e)
{
_control1.Visible = !RenderControl2;
_control2.Visible = RenderControl2;
}
In addition, you should save the value of RenderControl2 in the control state as described there. This way it will be persisted across postbacks.
When I use checkbox with a postback, my main class starts again at the first line. Therefore my variable changes again.
Like this:
public partial class Fırın1 : System.Web.UI.Page
{
bool Checkboxlist1value, Checkboxlist1value = false;
bool first_value=false;
protected void Page_Load(object sender, EventArgs e)
{
Panel1.Visible = false;
if (!Page.IsPostBack)
{
first_value = true;
}
}
}
As you can see in a small section of my code, when I click checkbox or save button class fırın_1 starts again at the first line. Thus first_value changes to false. But I need true because the condition will change this value to true.
How can I solve this problem?
Thanks in advance for your cooperation.
If you want to persist values across a PostBack, you should generally store them in ViewState.
If I understand what you're trying to achieve, you should change first_value from a field to a property that's backed by ViewState. For example (I've changed it from first_value to FirstValue in line with Microsoft guidelines):
public bool FirstValue
{
get
{
object o = ViewState["FirstValue"];
if (o == null) return false; // default is false
return (bool) o;
}
set
{
ViewState["FirstValue"] = value;
}
}
...
protected void Page_Load(object sender, EventArgs e)
{
Panel1.Visible = false;
if (!Page.IsPostBack)
{
FirstValue = true;
}
}
I have a custom class creating a dropdownlist control as below:
public class IHGridView : System.Web.UI.WebControls.WebControl
{
private string _dataSource = "not set yet";
public string DataSource
{
get { return _dataSource; }
set { _dataSource = value; }
}
}
EDIT:
protected override void OnInit(EventArgs e)
{
// VIewState is alive. When I select an option and submit, after postback it's selected value is the one I selected.
this.Controls.Add(_dropDownList);
}
or
protected override void CreateChildControls()
{
// VIewState is dead. When I select an option and submit, after postback it's selected value is the default one.
this.Controls.Add(_dropDownList);
}
So, now I come up with the result that I have to add control in "OnInit" void.
But, this "OnInit" is the first void that this class writes.
If I want to use a property like "DataSource" before, "OnInit" void...
How would I do that?
EDIT:
protected void Button1_Click(object sender, EventArgs e)
{
IHGridViewTest2.DataSource = "fired";
}
DataSource is set when the button in aspx page is fired.
why would you want to add _dropDownList twice? once in the OnInit should be enough, and OnInit is where it should be added if you want it in the control collection - thus having viewstate persisted and restored.
to access and bind _dropDownList for example, override the DataBind method - at which point all the properties will be available to you.
protected override void DataBind(){
base.DataBind();
_dropDownList.DataSource = this.DataSource;
_dropDownList.DataBind();
}
this is pseudo code, and has not been tested or validated
EDIT:
Call overriden DataBind method
protected void Button1_Click(object sender, EventArgs e)
{
IHGridViewTest2.DataSource = "fired";
IHGridViewTest2.DataBind();
}
I have created a composite control with sample details as follows. Basically, the first time on page load the control sets a view state variable and the problem is that on post back (when the button is clicked), the ViewState variable is null. I have researched extensively and I am not able to find a solution. I checked all the Microsoft recommended articles and also from other developers. This approach seem to work for everyone and I can't figure out what I'm doing wrong. If anyone can help, I would really appreciate it.
PS: This code may not work as it is only for illustrative purposes. but this is exactly what i'm doing in my code.
Public class Test : CompositeControl
{
private Button btnTest = new Button();
public string TestViewState
{
get
{
string s = (string)ViewState["test"];
return (s == null) ? String.Empty : s;
}
set
{
ViewState["test"] = value;
}
}
private void set()
{
TestViewState = "test";
}
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
set();
}
protected override void RecreateChildControls()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
base.Controls.Clear();
btnTest.ID = "btnTest";
btnTest.Click += new EventHandler(btnSubmitTest_Click);
if (!ChildControlsCreated)
Controls.Add(btnTest);
base.CreateChildControls();
}
protected override void Render(HtmlTextWriter writer)
{
btnSumbit.Render(writer);
}
protected void btnSubmitTest_Click(object sender, EventArgs e)
{
string test = TestViewState; // Viewstate value is null here!!!!!!
}
}
Are you sure that Page_Load is getting called? As far as I can remember that "notation" works only on pages and User Controls (didn't check that). Try overriding:
protected override void OnLoad(EventArgs e)
{
...
}
Test it with a Debugger.
Ok, the enableviewstate was disabled at the web.config level by another team member. Glad I found it. Thanks Arthur for confirming it worked for you.