Losing state of WebForm User Control - asp.net

First of all, I have no experiences with ASP.NET WebForms. However, I inherited a very old WebForm application where I have to do maintenance from time to time. This is such a situation:
There is a user control that has private instance variables. The problem is, that the values of these instance variables get lost, most likely after page reload. What I found out so far is, that it seems that the control class gets recreated frequently. What would be helpful, would be answers to the following questions:
Do WebForm User Controls do maintain a state?
If yes, how is it done in general (pointers to online resources for details appreciated)
If no, can it be implemented somehow? Any samples?

Probably the most common way to maintain state is to use ViewState rather than private instance fields. For example, if your UserControl contains a property Text, you can define it as follows:
public string Text
{
get { return (string) ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
You can also delegate a property to a child control. In this case the child control will maintain ViewState for you (provided EnableViewState is true). For example:
public string Text
{
get { return MyTextBox.Text; }
set { MyTextBox.Text = value; }
}
Google for ViewState for more info. There are pitfalls and it's a good idea to understand it thoroughly.

Related

How to make a web user control public

My page contains several web user controls. Those controls contains other child controls, and those contains more child controls and so on. From my page, I want to be able to access those controls, like I do with other public classes: uc1.uc1_child1.uc1_child1_child1.Update();
(I do know about the FindControl method, and thats what Im currently using. It's however not type safe, and I need to lookup the names of the controls all the time to be on safe side. Much more time consuming than intellisense)
If you create a public property on your usercontrol for each of the usercontrols it contains, that should work.
eg
public SpecificUserControlType ContainedUserControl
{
get
{
return this.uc1_child;
}
}

ASP.NET 4.0: Is it possible to make some user control's child controls public without using FindControl or public properties?

I have a custom user control that contains text boxes, dropdowns, etc. I need these controls to be public so that I can go like ucEmployeeAddress.txtAddr1.Text from outside the control.
I know that I can use public properties in the control that return an instance of the control inside or use FindControl to locate my control from outside the user control, but I don't want to do that due to excess code.
If there is no way to do what I want then I will just go the public property route.
Edit: Would the person who thumbed my question down be so kind as to explain how my question shows lack of research effort, is unclear, or not useful?
You just need to expose a property in the user control:
public string Address
{
get
{
return txtAddr1.Text;
}
set
{
txtAddr1.Text = value;
}
}
Do you really need to expose the entire control ?
If its just the text property you could just expose that.
public string TitleText
{
get { return this.txtTitle.Text;}
}
If you really need the control i would suggest exposing it via a property, consumers may not even know the existance or name of the control, and nor should they care about your internal workings - using FindControl is a poor solution from outside of the control.
public TextBox TitleTextBox
{
get { return this.txtTitle;}
}
As an alternative you may be able to modify the visual studio templates to expose all your controls as public, however im not sure if this is such a great idea or how you would do it..
Well, about three hours later, I finally came upon a solution. I don't know if this is new in VS2010, but you can actually edit the user control's designer and turn all members from Protected to Public. I swear I've tried this with earlier versions of VS in the past without success, but it's apparently working for me now.
What's interesting is that the IDE has a keen sense of what parts of the designer it should and should not regenerate. For example, if you comment out the entire contents of the designer class, it will not regenerate the commented-out members. To get it to regenerate them, you have to completely delete the members that you want regenerated. What's also cool is that you can comment out the entire designer class's contents, switch back to the markup and add a server control like a textbox, and flip back to the designer to discover that it generated the member definition for only that control while the rest of the member references remain commented-out. Edit: And if you delete a control from the markup whose designer member you had modified from protected to public, it will still delete the reference from the designer.
I will note that I am also using VB.NET. I would have to assume this works with C#, as well, but cannot say for sure.
The proper way to do this is through event bubbling. This way you can keep the implementation of your controls hidden while being able to modify the properties that you chose.
This link does a good job explaining how to accomplish this.
As a side note, you should be more concerned with the elegance of your code than the amount of it.
If you take the time to implement event bubbling, for example, as opposed to exposing the control's children as public, any manipulation of the control's children is handled by that control. This makes it easy to maintain if ever the logic of manipulation were to change, and easy to implement across your entire application.
However, if you expose your control's children as public instead, you must repeat that manipulation everywhere it is used.
Therefore, the "excess code" will both improve the quality of your code and actually decrease this "excess code" you are concerned about.

Maintaining dynamic control state between postbacks

I have a dynamic ASP.NET form which I recreate evertime I postback. My values persist no problem.
I am however having a challenge maintaining attributes on Postback. For example, I have user defined code which may enable or disable a field when someone is first presented with the form. If a user posts the form I need an easy way to make sure the field stays enabled or disabled.
Does this make sense? Is there an easy way to do this?
ViewState is the preferred method of persisting information between postbacks that doesn't need to live beyond the scope of a single page. You can store information pretty easily there.
An easy way to accomplish this is to use a property in the control, or the page that abstracts the use of ViewState from you.
protected Boolean IsFieldVisible
{
get{ return (Boolean)ViewState["SomeUniqueKey"] ?? false; }
set{ ViewState["SomeUniqueKey"] = value; }
}
This will maintain the value between postbacks.

Dynamically create Public Properties

How dan I dynamically create some public properties on a custom webcontrol.
For example, web control has 5 TextBox controls. I need a public property for each TextBox control to be able to set a specific property of the TextBox control.
I want to be able to loop the controls in the webcontrol and create a public property for each TextBox control.
any ideas?
Edited:
If the child-controls are present at Design-Time then you need to explain why you want to dynamically add properties to access the control members--unless there is a good reason it just sounds like a poor design.
Here's my suggestion:
Leave your controls as Friend or Private -- don't expose them directly (it leads to tight-coupling and gets nasty over time).
Expose a new public property that gets/sets the corresponding property on 1x of your controls; so if you want to set .Text on 5x TextBoxes you'll have 5x properties.
Be done with it.
If you're trying to be clever by dynamically adding them, then it's a good intention that will lead to poor results. Just remember: KISS (Keep it simple, stupid!).
You could create a property like this
private TextBox[] textBoxes; //declared as a class member variable
public TextBox[] TextBoxes
{
get
{
if (textBoxes == null)
{
textBoxes =(from ctrl in this.Controls.OfType<Control>()
where ctrl is TextBox
select (TextBox)ctrl).ToArray();
}
return textBoxes;
}
}
Exposing the controls contained in a WebContol (or any class for that matter) is not a good design as it makes your code brittle and hard to maintain. You should put code that directly manipulates the TextBoxes inside the WebControl.

asp.net code behind variable

I am generating some head html in page load and because of that I query database once. in the page I query database again and put data into html with inline code.
my question is is there better way to do this? I dont want to query database everytime and reach out those filled variables from inline code. something like page.addVariable in page_load and reach those at inline like page.variables["variablename"]
thanks in advance
If I understand what you are asking, you can make an accessor and set it to Protected. That will allow you to access it from the page.
If you want to prevent calling the database on callbacks, you could always add the information to the view state on the page.
Information on the view state, hidden fields, and cookies:
http://www.csharphelp.com/archives/archive207.html
I'm not sure if this is what you're after, but you can use a HiddenField to store any data you want on the page.
Also, if you don't need it to be on the page, you can use Session or ViewState.
Here's an example of using ViewState as a property (NB. you can interchange ViewState with Session, look at the links I gave you for an explanation between the two):
public string YourProperty
{
get
{
object content = ViewState["YourProperty"];
if (content == null)
{
return string.Empty;
}
return content.ToString();
}
set
{
ViewState["YourProperty"] = value;
}
}
Note, that anything you put into ViewState or SessionState must be marked as Serializable.
If it's quite a simple class, just mark the class with the [Serializable] tag.
Is the data you retrieve from the database page specific, user specific or global to the entire application?
If the data is user specific you can use Session State.
If the data is global to the entire application you could use Application State.
Whichever you use, you can implement the data retrieval in the Session_Start (will be called only once for each user) or Application_Start (will be called only once when the web app starts) events in a Global.asax file.

Resources