I have a custom control that has a hidden field. Upon postback I want to obtain the value stored in it, but it's always an empty string. any thoughts?
I am performing client-side manipulation of the hidden field values and have verified in firebug that the fields are correct before issue a post back
Here is the setup:
public class DualListPanel : SWebControl, INamingContainer
{
protected IList<DlpItem> UnassignedList { get; set; }
protected IList<DlpItem> AssignedList { get; set; }
private HiddenField assignedItemsField, unassignedItemsField;
public DualListPanel()
{
CssClass = "DualListPanel";
EnableViewState = true;
}
#region ViewState
protected override void LoadViewState(object savedState)
{
var state = savedState as object[];
UnassignedList = state[0] as List<DlpItem>;
AssignedList = state[1] as List<DlpItem>;
base.LoadViewState(state[2]);
}
protected override object SaveViewState()
{
object[] state = new object[3];
state[0] = UnassignedList;
state[1] = AssignedList;
state[2] = base.SaveViewState();
return state;
}
#endregion
#region WebControl Overrides
protected override void OnInit(EventArgs e)
{
EnsureChildControls();
GetUnassignedList(); //omitted method
GetAssignedList(); //omitted method
base.OnInit(e);
}
protected override void CreateChildControls()
{
assignedItemsField = new HiddenField();
assignedItemsField.ID = "HiddenAssignedItems";
assignedItemsField.EnableViewState = true;
unassignedItemsField = new HiddenField();
unassignedItemsField.ID = "HiddenUnassignedItems";
unassignedItemsField.EnableViewState = true;
Controls.Add(assignedItemsField);
Controls.Add(unassignedItemsField);
base.CreateChildControls();
}
#endregion
#region Item Lists Retrieval
public string GetCommaDelimUnassignedItems()
{
return unassignedItemsField.Value;
}
public string GetCommaDelimAssignedItems()
{
return assignedItemsField.Value;
}
#endregion
}
I think hidden field's value does not lost during postback,
Put your code in Ispostback, whenever you initialize hidden fields.
protected override void CreateChildControls()
{
if(!ispostback){
assignedItemsField = new HiddenField();
assignedItemsField.ID = "HiddenAssignedItems";
assignedItemsField.EnableViewState = true;
unassignedItemsField = new HiddenField();
unassignedItemsField.ID = "HiddenUnassignedItems";
unassignedItemsField.EnableViewState = true;
Controls.Add(assignedItemsField);
Controls.Add(unassignedItemsField);
base.CreateChildControls();
}
}
Ugggh I omitted information that would have been useful. I was primarily testing if I could access the values during the page cycle process. Not necessarily from a page calling
GetCommaDelimUnassignedItems();
I realized I had implemented OnInit() and made calls to check the value (I omitted it thinking it was not useful to the issue). Completely forgot that the ViewState will not be loaded during OnInit(). I changed it to OnPreRender() and it's working fine now
It looks like you simply need to mark your 2 hidden fields protected instead of private.
Related
I've created Session Variables as Objects from the tutorial http://www.c-sharpcorner.com/uploadfile/9505ae/session-variables-as-objects/
I have given the values of the session from login page LoginUser.aspx .
I am trying to check if the session values are empty or not in Base Page. When I login from the login page and redirects to another page, the session values are checked in base page. The session values in Base page are always NULL. I can not retrieve the session values set from LoginUser.aspx in Base page class.
public class C_UserSession
{
#region Variables
private const string mySessionName = "_MyUserInfo_"; //Our session name
private string username;
private string role;
private string name;
#endregion
#region constructor
public C_UserSession()
{
}
#endregion
#region Public Methods
public string UserName
{
get { return this.username; }
set { this.username = value; Save(); }
}
public string Role
{
get { return this.role; }
set { this.role = value; Save(); }
}
public string Name
{
get { return this.name; }
set { this.name = value; Save(); }
}
#endregion
#region Private Methods
private void CheckExisting()
{
if (HttpContext.Current.Session[mySessionName] == null)
{
//Save this instance to the session
HttpContext.Current.Session[mySessionName] = this;
UserName = string.Empty;
Role = string.Empty;
Name = string.Empty;
}
else
{
//Initialize our object based on existing session
C_UserSession oInfo = (C_UserSession)HttpContext.Current.Session[mySessionName];
this.UserName = oInfo.UserName;
this.Name = oInfo.Name;
this.Role = oInfo.Role;
oInfo = null;
}
}
private void Save()
{
//Save our object to the session
HttpContext.Current.Session[mySessionName] = this;
}
#endregion
}
login page code behind logic
public partial class LoginUser : System.Web.UI.Page
{
C_UserSession usersession;
protected void Page_Load(object sender, EventArgs e)
{
Session.Clear();
Session.Abandon();
usersession = new C_UserSession();
}
protected void btnSignIn_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt = new C_User().Get_LoginUser(inputUserName.Value, inputPwd.Value);
if (dt == null || dt.Rows.Count == 0)
{
Response.Redirect("LoginUser.aspx", false);
return;
}
DataRow dr = dt.Rows[0];
usersession.UserName = dr["USERNAME"].ToString();
usersession.Name = dr["NAME"].ToString();
usersession.Role = dr["ROLE"].ToString();
Int16 userRole = Convert.ToInt16(usersession.Role);
Dictionary<int, string> _redirects = new Dictionary<int, string>
{
{ 1, "product.aspx"}, {2, "shift.aspx" }
};
Response.Redirect(_redirects[userRole], false);
}
}
base page code behind
public class BasePage : System.Web.UI.Page
{
C_UserSession usersession;
public BasePage() {
usersession = new C_UserSession();
}
protected override void OnInit(EventArgs e)
{
try
{
if ( string.IsNullOrEmpty(usersession.UserName) || string.IsNullOrEmpty(usersession.Role))
{
Response.Redirect("LoginUser.aspx");
Context.ApplicationInstance.CompleteRequest();
}
}
catch (Exception ex)
{
throw;
}
}
}
product page inherits Base Page
public partial class product : BasePage
{
// code blocks
}
When I open my product.aspx page, it redirects me to LoginUser.aspx because session values are null. But after providing valid username and password also, I can not go the respective pages. I can not check the session values from Base Page. I can not understand what is the correct approach to do this. Please help. Thank You!!!
Here is the issue. In your BasePage you have this code:
public class BasePage : System.Web.UI.Page
{
C_UserSession usersession;
public BasePage()
{
usersession = new C_UserSession();
}
protected override void OnInit(EventArgs e)
{
try
{
if (string.IsNullOrEmpty(usersession.UserName) || string.IsNullOrEmpty(usersession.Role))
{
}
}
}
}
But off course usersession.Userame will be empty because you just created it in the constructor.
What you should be doing is checking the session to see if it is there and if not, then do a redirect:
public class BasePage : System.Web.UI.Page
{
C_UserSession usersession;
public BasePage()
{
usersession = (C_UserSession)HttpContext.Current.Session[mySessionName];
}
protected override void OnInit(EventArgs e)
{
try
{
if (usersession == null)
{
Response.Redirect("LoginUser.aspx");
Context.ApplicationInstance.CompleteRequest();
}
}
}
}
Now you may have other issues in your code but that is the answer to your question.
Please do yourself a favor: If you are coding in C# then follow the C# coding conventions. Stop using names like C_UserSession and call it something without the underscore such. Do not call your class product but call it Product (Pascal Notation) or better yet call it ProductPage. Take some time and study your code and clean it up.
I don't think you are ever initializing your user object. You have a CheckExisting() private method on your class which appears to re-hydrate the class from session if it's there, but this is never called. If you don't call this within your class then it won't fill those properties and they will always be the default.
I am trying to study control state when i came across an article in code project
http://www.codeproject.com/Articles/331981/A-Beginner-s-Tutorial-Understanding-ControlState-i
But in that example only "Text" value is kept in control state, what if i have to keep both of them?
So i tried this code
protected override void OnInit(EventArgs e)
{
Page.RegisterRequiresControlState(this);
base.OnInit(e);
}
protected override object SaveControlState()
{
object[] state = new object[2]; // save the 2 properties
state[0] = Text;
state[1] = Text1;
return state;
}
protected override void LoadControlState(object savedState)
{
object[] state = (object[])savedState;
Text = (string)state[0];
Text1 = (string)state[1];
}
But it doesn't seem to work.. Can anyone please help me out ???
Thanks in advance
You can use a dictionary or List instead of array
protected override object SaveControlState()
{
var state = new List<string>(); // save the 2 properties
state.Add(Text);
state.Add(Text1);
return state;
}
protected override void LoadControlState(object savedState)
{
var state = (List<string>)savedState;
Text = state[0];
Text1 = state[1];
}
In a page, I have an event handler that sets 'Visible' to false on one control and true on another. Stepping through debug, I see that these values get set properly, and the control marked visible goes through OnPreRender while the control I have set to invisible does not. So all of that seems to be working as expected. However, when the request completes, the visibility has not changed at all on the page. I've tried setting the directly parent UpdatePanel to 'always' and have tried manually calling 'Update()' on it with no effect. Any clue as to what is going on here?
UPDATE:
I have found that it is only setting a private property on my user control that causes this whole thing to not work. I have included an example of that control and all of the places it references the private field.
Example:
protected override void OnLoad(EventArgs e)
{
if (this.IsPostback)
{
return;
}
this.Control1.Visible = true;
this.Control2.Visible = false;
}
protected void OnButtonClicked (object sender, EventArgs e)
{
this.Control1.Visible = false;
this.Control2.Visible = true;
// this has desired results when it fires
}
protected void OnUserControlEventThatFiresAfterRowCommand (object sender, EventArgs e)
{
this.Control2.SomeProp = this.GetSomeObject();
this.Control1.Visible = false;
this.Control2.Visible = true;
// this does not have desired results, even though it does fire
}
And then in Control2:
private SomeClass privatefield;
public SomeClass SomeProp
{
get
{
return this.privatefield;
}
set
{
this.PopulateFields(value);
this.privatefield = value;
// If I comment out this line it works!
}
}
protected override void LoadViewState(object savedState)
{
object[] state = savedState as object[];
base.LoadViewState(state[0]);
this.Enabled = state[1] as bool? ?? true;
this.SomeProp = state[2] as SomeClass;
this.Visible = state[3] as bool? ?? true;
}
protected override object SaveViewState()
{
return new object[]
{
base.SaveViewState(),
this.Enabled,
this.SomeProp,
this.Visible
};
}
I finally found out why by looking at the actual response body.
156|error|500|Error serializing value 'withheld class name' of type 'withheld class name'|
Why this error was not being thrown in debug is beyond me, but for anyone else reading this question looking for answers, look at your response bodies! It is because I was trying to put my instance of a class into Viewstate but that class was not marked with the Serializable attribute.
I'm trying to develop a Custom ASP.Net Server Control, which can be manipulated at the client. To save the changes after a Postback there is a hidden field. On the OnLoad event I retrieve the value to write the Property, but it seems too late, because the controls are already built. I know I could manipulate the controls on the PreRender event, but to me it seems there is a better way to handle this. Anyone an idea?
public class Control : CompositeControl {
private bool mProperty;
private HiddenField hiddenField;
public virtual bool Property {
get {
return mProperty;
}
set {
mProperty = value;
}
}
protected override void CreateChildControls() {
Controls.Clear();
CreateControlHierarchy();
ClearChildViewState();
}
protected virtual void CreateControlHierarchy() {
CreateHiddenField();
CreateContent();
}
protected virtual void CreateHiddenField() {
hiddenField = new HiddenField();
hiddenField.ID = "hiddenField";
hiddenField.Value = Property.ToString().ToLower();
Controls.Add(hiddenField);
}
protected virtual void CreateContent() {
contentPanel = new Panel();
contentPanel.ID = "content";
contentPanel.Vsiible = Property;
Controls.Add(contentPanel);
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if(Page.IsPostback) {
Property = Convert.ToBoolean(Page.Request.Form[hiddenField.UniqueId]);
}
}
}
Edit Possible Solution:
I got rid of the OnLoad event and edited the property like so:
public virtual bool Property {
get {
if (Page.IsPostBack) {
EnsureChildControls();
return Convert.ToBoolean(Page.Request.Form[hiddenField.UniqueID]);
}
return mProperty;
}
set {
mProperty = value;
}
}
Is that a good approach?
One suggestion is to set the post back value both on Property and on control, because the property is used only when the control is created.
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
if(Page.IsPostback) {
if(hiddenField != null)
hiddenField.Value = Page.Request.Form[hiddenField.UniqueId].ToString();
Property = Convert.ToBoolean(Page.Request.Form[hiddenField.UniqueId].ToString());
}
}
I achieved what I wanted to do, by implementing a ValueChanged EventHandler for the hidden field and edit the setter of the property to take care of all dependencies.
public class Control : CompositeControl {
private bool mProperty;
private HiddenField hiddenField;
public virtual bool Property {
get {
return mProperty;
}
set {
mProperty = value;
if (contentPanel != null) contentPanel.Visible = value;
if (hiddenField != null && hiddenField.Value != value.ToString().ToLower()) hiddenField.Value = value.ToString().ToLower();
}
}
protected override void CreateChildControls() {
Controls.Clear();
CreateControlHierarchy();
ClearChildViewState();
}
protected virtual void CreateControlHierarchy() {
CreateHiddenField();
CreateContent();
}
protected virtual void CreateHiddenField() {
hiddenField = new HiddenField();
hiddenField.ID = "hiddenField";
hiddenField.Value = Property.ToString().ToLower();
hiddenField.ValueChanged += hiddenField_ValueChanged;
Controls.Add(hiddenField);
}
protected virtual void CreateContent() {
contentPanel = new Panel();
contentPanel.ID = "content";
contentPanel.Vsiible = Property;
Controls.Add(contentPanel);
}
void hiddenField_ValueChanged(object sender, EventArgs e) {
Property = Convert.ToBoolean(hiddenField.Value);
}
protected override void OnInit(EventArgs e) {
EnsureChildControls();
base.OnInit(e);
}
}
Not found anything that directly answers my problem, so hopefully someone can shed some light on it.
I have two Composite Controls, lets call them BudgetTable and BudgetTableItem, where BudgetTable contains a list of BudgetTableItem.
So far everything works so long as I add new RowItems in the HTML View - when I add one programmatically it appears, but doesn't survive postback.
I can only assume I'm doing something boneheaded with ViewState, and would appreciate any pointers!
Thanks in advance.
The HTML:
<hea:BudgetTable runat="server" ID="btTest" MaximumFundingAvailable="7000" CssClass="bob">
<Items>
<hea:BudgetTableItem runat="server" Description="Test1" />
<hea:BudgetTableItem runat="server" Description="Test2" />
<hea:BudgetTableItem runat="server" Description="Test3" />
</Items>
</hea:BudgetTable>
The code behind:
[PersistenceMode(PersistenceMode.InnerProperty)]
[ParseChildren(true)]
public class BudgetTableItem : CompositeControl {
private TextBox _description = new TextBox();
private TextBox _cost = new TextBox();
private CheckBox _heaFunded = new CheckBox();
/*public delegate void AddRow();
public delegate void RemoveRow(BudgetTableItem item);
public event AddRow AddNewRow;
public event RemoveRow RemoveNewRow;*/
public string ItemName {
get {
var viewstate = ViewState["ItemName"];
return (viewstate is string) ? (string)viewstate : "default";
}
set {
ViewState["ItemName"] = value;
}
}
public bool ShowRemoveRow {
get {
var viewstate = ViewState["ShowRemoveRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowRemoveRow"] = value;
}
}
public bool ShowAddRow {
get {
var viewstate = ViewState["ShowAddRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowAddRow"] = value;
}
}
public string Description {
get {
return _description.Text;
}
set {
_description.Text = value;
}
}
public decimal Cost {
get {
decimal cost =0;
decimal.TryParse(_cost.Text, out cost);
return cost;
}
set {
_cost.Text = value.ToString();
}
}
public bool HeaFunded {
get {
return _heaFunded.Checked;
}
set {
_heaFunded.Checked = value;
}
}
protected override void CreateChildControls() {
Controls.Clear();
HtmlTableCell tableCell1 = new HtmlTableCell();
HtmlTableCell tableCell2 = new HtmlTableCell();
HtmlTableCell tableCell3 = new HtmlTableCell();
HtmlTableCell tableCell4 = new HtmlTableCell();
tableCell1.Attributes.Add("class", "col1");
tableCell2.Attributes.Add("class", "col2");
tableCell3.Attributes.Add("class", "col3");
tableCell4.Attributes.Add("class", "col4");
tableCell1.Controls.Add(_description);
tableCell2.Controls.Add(_cost);
tableCell3.Controls.Add(_heaFunded);
/*if (ShowAddRow || ShowRemoveRow) {
Button addNewButton = new Button();
addNewButton.Text = (ShowAddRow) ? "Add Row" : "Remove";
if (ShowAddRow) {
addNewButton.Click += new EventHandler(addNewButton_Click);
}
if (ShowRemoveRow) {
addNewButton.Click += new EventHandler(removeButton_Click);
}
tableCell4.Controls.Add(addNewButton);
}
else{*/
tableCell4.InnerHtml = " ";
//}
Controls.Add(tableCell1);
Controls.Add(tableCell2);
Controls.Add(tableCell3);
Controls.Add(tableCell4);
}
/*void addNewButton_Click(object sender, EventArgs e) {
if (AddNewRow != null) {
AddNewRow();
}
}*/
/*void removeButton_Click(object sender, EventArgs e) {
if (RemoveNewRow != null) {
RemoveNewRow(this);
}
}*/
protected override void RecreateChildControls() {
EnsureChildControls();
}
public override void RenderBeginTag(HtmlTextWriter writer) {
writer.Write("<tr>");
}
public override void RenderEndTag(HtmlTextWriter writer) {
writer.Write("</tr>");
}
}
Controls, custom or otherwise that require a ViewState and wish to receive events should be created in Init.
Http is stateless. Your entire page with all its controls is recreated on every postback. Controls that you add in the design view, are added to your designer.cs file, and created for you. When you add controls yourself, you must write code to recreate the controls on every PostBack that occurs later.
You can use the session to remember which controls were added by code and add them on later PostBacks.