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];
}
Related
I got an issue with my Android program when updating user data on Fragment_profile. Fragment_Profile loads User profile data and contains an update button in which the button navigates to an activity called EditProfileActivity. Users can technically update the data but, after they save the updated data, the data still can't be updated. The old data still appear. I try to refresh the fragment by using OnResume() and add OnRestart on my EditProfileActivity.cs and OnPause both in fragment and activity but, still nothing. I am using Xamarin Android and develop it with C#. For more info, you can see what happened in the GIF
My issue
So far, I've tried to code, and here's my code.
Fragment_profile.cs
public class Fragment_Profile : Android.Support.V4.App.Fragment
{
public HomePageActivity m_currentActivity;
public TextView m_tv_loginname, m_tv_username, m_tv_fullname , m_tv_dob;
public Boolean isRefreshing = false;
public override void OnCreate(Bundle aSavedInstanceState)
{
base.OnCreate(aSavedInstanceState);
}
//public static Fragment_Profile NewInstance(Model.User aCurrentUser)
public static Fragment_Profile NewInstance()
{
var _frag4 = new Fragment_Profile { Arguments = new Bundle() };
return _frag4;
}
public override View OnCreateView(LayoutInflater aInflater, ViewGroup aContainer, Bundle aSavedInstanceState)
{
var _ignored = base.OnCreateView(aInflater, aContainer, aSavedInstanceState);
var view= aInflater.Inflate(Resource.Layout.FragmentProfile, null);
m_tv_loginname = view.FindViewById<TextView>(Resource.Id.tv_loginname);
m_tv_username = view.FindViewById<TextView>(Resource.Id.tv_userEmail);
m_tv_fullname = view.FindViewById<TextView>(Resource.Id.tv_fullname);
m_tv_dob = view.FindViewById<TextView>(Resource.Id.tv_dob);
Button _updateProfile = view.FindViewById<Button>(Resource.Id.btnUpdateProfile);
_updateProfile.Click += _updateProfile_Click;
m_currentActivity = (HomePageActivity)this.Activity;
if (m_currentActivity.CurrentUser != null)
{
//string = "Welcome, " + m_currentActivity.CurrentUser.UserName;
m_tv_loginname.Text = m_currentActivity.CurrentUser.LoginName;
m_tv_fullname.Text = m_currentActivity.CurrentUser.UserName;
m_tv_username.Text = m_currentActivity.CurrentUser.UserEmail;
m_tv_dob.Text = m_currentActivity.CurrentUser.DateOfBirth;
}
else
{
Toast.MakeText(Activity, "The data is not found!", ToastLength.Short).Show();
Intent i = new Intent(Context, typeof(MainActivity));
StartActivity(i);
this.Activity.Finish();
}
return view;
}
private void _updateProfile_Click(object sender, EventArgs e)
{
Intent i = new Intent(Context, typeof(EditProfileActivity));
i.PutExtra("loginname", m_currentActivity.CurrentUser.LoginName);
i.PutExtra("fullname", m_currentActivity.CurrentUser.UserName);
i.PutExtra("useremail", m_currentActivity.CurrentUser.UserEmail);
i.PutExtra("dob", m_currentActivity.CurrentUser.DateOfBirth);
StartActivity(i);
}
public override void OnResume()
{
base.OnResume();
if (isRefreshing)
{
Fragment fragment = new Fragment_Profile();
Android.Support.V4.App.FragmentManager fragmentMg = Activity.SupportFragmentManager;
FragmentTransaction fragmentTrans = fragmentMg.BeginTransaction();
fragmentTrans.Replace(Resource.Id.content_frame, fragment);
fragmentTrans.Detach(fragment);
fragmentTrans.Attach(fragment);
fragmentTrans.Commit();
//adapter.notifyDataSetChanged();
}
}
public override void OnPause()
{
base.OnPause();
isRefreshing = true;
}
}
When user click the _updateProfile button It will reference to next activity which is EditProfileActivity. Here's my EditProfileActivity.cs
public class EditProfileActivity : Activity, IOnDateSetListener
{
public EditText m_editFullName, m_editUsername, m_dob;
public TextView m_tvEmail;
public Button m_btnUpdate;
public Boolean isRefreshing = false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.EditProfile);
m_editFullName = FindViewById<EditText>(Resource.Id.et_editfullName);
m_editUsername = FindViewById<EditText>(Resource.Id.et_editUserName);
m_tvEmail = FindViewById<TextView>(Resource.Id.tv_Email);
m_dob = FindViewById<EditText>(Resource.Id.et_editDob);
m_btnUpdate = FindViewById<Button>(Resource.Id.btn_updateprofile);
m_btnUpdate.Click += _btnUpdate_Click;
m_dob.Click += _dob_Click;
Bundle extras = Intent.Extras;
m_editFullName.Text = extras.GetString("loginname");
m_editUsername.Text = extras.GetString("fullname");
m_tvEmail.Text = extras.GetString("useremail");
m_dob.Text = extras.GetString("dob");
}
private void _btnUpdate_Click(object sender, EventArgs e)
{
try
{
Model.User _currentUser = Model.User.CheckEmailUser(m_tvEmail.Text);
_currentUser.UserName = m_editUsername.Text;
_currentUser.LoginName = m_editFullName.Text;
_currentUser.UserEmail = m_tvEmail.Text;
_currentUser.DateOfBirth = m_dob.Text;
var _updated = DBManager.Instance.Update(_currentUser);
if (_updated > 0)
{
Toast.MakeText(this, "Your account has been succesfully updated!", ToastLength.Long).Show();
Finish();
OnResume();
}
else
{
Toast.MakeText(this, "Failed to update!", ToastLength.Long).Show();
}
}
catch(Exception ex)
{
Toast.MakeText(this, ex.ToString(), ToastLength.Short).Show();
}
}
private void _dob_Click(object sender, EventArgs e)
{
var _dateTimeNow = DateTime.Now;
DatePickerDialog _datepicker = new DatePickerDialog(this, this
, _dateTimeNow.Year, _dateTimeNow.Month, _dateTimeNow.Day);
_datepicker.Show();
}
public void OnDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
m_dob.Text = new DateTime(year, month + 1, dayOfMonth).ToShortDateString();
}
protected override void OnRestart()
{
base.OnRestart();
if (isRefreshing)
{
isRefreshing = false;
Finish();
}
}
protected override void OnPause()
{
base.OnPause();
if (!isRefreshing)
isRefreshing = true;
}
}
I also have read some articles that have the same problems as me but, It still confusing me and still same. I know it's a simple thing but, It took a few days for me because I am a newby and I still don't get the solution.
Do you guys have any ideas? Would you like to help me? If you don't mind please check my source code so, I know what I am missing. Thank in advance for your help!
In you Fragment, you can override the OnResume method. If you back to the fragment from Acitivty. you should query the new data from DB, then set the new value to the controls in Fragment.
public override void OnResume()
{
base.OnResume();
PHName.Text = photoDAO.GetFirstPhotos(Id).PhotoName;
}
Here is running GIF.
You can see this lifecycle about Fragment. Every time you display the Fragment,OnResume method will be executed. You get the newest data from DB, then set it to the Fragment page.
Here is my demo.
https://drive.google.com/file/d/11dROKS7TtqAaVYkG8w6ZKpqnQJRBD87E/view
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);
}
}
I have small problem with retrieving the state of a canvas' visibility property. When I retrieve the page state, the canvas is always visible even if it was collapsed when it was tombstoned. I tried a bunch of if else and switch statements but with no luck. How do I fix this bug? Thanks in advance to anyone who wants to help!
Here's the code:
private const string coachPivotKey = "CoachPivotKey";
private const string isVisibleKey = "IsVisibleKey";
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
this.SaveState(coachPivotKey, coachPivot.SelectedIndex);
this.SaveState(isVisibleKey, canvasNotes.Visibility);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
coachPivot.SelectedItem = coachPivot.Items[this.LoadState<int>(coachPivotKey)];
canvasNotes.Visibility = this.LoadState<Visibility>(isVisibleKey);
base.OnNavigatedTo(e);
}
The LoadState() and SaveState() methods are in a different class. These I got from a video I watched on tombstoning:
public static void SaveState(this PhoneApplicationPage phoneApplicationPage, string key, object value)
{
if (phoneApplicationPage.State.ContainsKey(key))
{
phoneApplicationPage.State.Remove(key);
}
phoneApplicationPage.State.Add(key, value);
}
public static T LoadState<T>(this PhoneApplicationPage phoneApplicationPage, string key)
{
if (phoneApplicationPage.State.ContainsKey(key))
{
return (T)phoneApplicationPage.State[key];
}
return default(T);
}
Instead of saving a System.Windows.Visibility, save a bool indicating whether the control is visible.
this.SaveState(isVisibleKey,coachNotes.Visibility == Visibility.Visible);
canvasNotes.Visibility = this.LoadState<bool>(isVisibleKey) ? Visibility.Visible : Visibility.Collapsed;
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.