Persisting a control's properties - c#

OK Time for another dumb Q from yours truly.
I have a control that has some properties that need to be persisted in the ViewState. I also need to make sure that the properties aren't overwritten if the control appears more than once on the page.
I thought to write something like...
ViewState[String.Format("{0}_{1}", "BaseKey", this.ClientID)] = ...
But the value of ClientID changes partway through the page's lifecycle. It starts out as something like "MyControl1" and then becomes "ctl001_MyControl1". So any values applied before it changes are lost.
The same thing happens if I use UniqueID instead.
I know I'm missing something obvious, and I'm going to blame the pills I'm taking so I don't look too dumb.
--
Stuart

it looks like you are doing this inside the user control, if that is true you do not need to make a unique key for the viewstate, each instance of every control manages it's own viewstate so all you need is a key known to your control, something like that:
ViewState[#"somekey"] = ...

Try doing it on Page_PreRender rather than Page_Load?

Don't store the value named relative to the output name of the control itself. Provide it with a unique, unchanging name and then make sure all of your binding rules adjust to that name instead of the client name.
Edit:
As a small example of what I mean:
MyControl ctrl1 = new MyControl();
ctrl1.ID = "MyControlA";
ctrl1.Text = "Some text";
ViewState[ctrl1.ID] = ctrl1.Text;
MyControl ctrl2 = new MyControl();
ctrl2.ID = "MyControlB";
ctrl2.Text = "Some other text";
ViewState[ctrl2.ID] = ctrl2.Text;

Related

Viewstate value erased when using Control

A little new to asp.net.
In my main.aspx page i have:
<users:UsersControl runat="server" ID="usersControl" />
In my UserControl page_load i have:
ViewState["test"] = "test";
In my Page_PreRender in main.aspx.cs:
log...(ViewState["test"]); <-- empty
Why dont i see the value on test?
Im guessing here that the ViewState collection is different in the two contexts you have mentioned.
The first is in the context of the control, and the second is in the context of the page, therefore "test" key is not shared between them.
Also, it is not a good idea to expose a controls ViewState beyond the control boundary. For example use properties on the UserControl as the interface to the viewstate, e.g
public string Test
{
get { return this.ViewState["Test"]; }
set { this.ViewState["Test"] = value; }
}
ViewState should be considered an internal implementation detail of the user control.
Then whenever you need to use this property from the page:
this.userControl1.Test = "This Goes Into ViewState";
I've found a similar answer to your question:
.net ViewState in page lifecycle
It's necessary to understand the life cycle, so why don't use Attributes on the UserControl?

Page.Request in OnLoad of a Server Control

In the OnLoad of a server control I would like to do the following:
string username = Page.Request["UsernameTextBox"];
The actual controls are then created in CreateChildControls (so I will only need to do this on a postback).
The problem is that I cannot use the IDs in this way, because the control in this case must be referenced by name.If I hard code it i can solve the problem by doing this:
string username = Page.Request["ctl02$ctl00$ctl02$ctl00$ctl02$ctl03$ctl03$ctl02$ctl01"];
Of course this would be a bad solution considering that the control hierarchy could change. So my question is this: Is there a way for me to get this control name in OnLoad. If I could find the method that calculates the name from the NamingContainer or something i would be fine.
(Let's not discuss this wierd design in this login control/page - consider it as the constant of my question).
You can set the ClientIDMode property of your username textbox to static.
http://msdn.microsoft.com/en-us/library/system.web.ui.clientidmode.aspx

Dynamically change value of hidden field

For an existing site, I have to pass values in hidden fields from a form that's loaded by different pages (eg. City1.aspx, City2.aspx, City3.aspx, etc.), but they are loaded inside an iframe. I also have to dynamically change the value of at least one of those hidden field (let's call it "source") based on the city page loading it. I am familiar with PHP and JavaScript/JQuery, but I have no idea how to do this in C#.
I've found tutorials on retrieving the file name (sans extension) via JavaScript. I think I can still get the city even if the form is in an iframe, but I'd like to keep to the site's conventions and use C# if possible.
Code snippets or links to possible solutions would be much appreciated.
if you want modify the value of your input in c# associated to your aspx (Code behind), you must to add attributes runat=server to your input.
use this code in your aspx
<input id="test" type="hidden" runat="server"/>
and in your c#
test.Value = 123; //your value is 123 for example
Disclaimer, I don't know JQuery, so there could be easier ways to do this. I also haven't tested any code...
If you know the exact ID then you can do something like this from the parent page (in a javascript block):
var frame = document.getElementById('myIFrame');
var ctrl = frame.document.getElementById('myControl');
ctrl.value = "New Value";
If you don't know the exact ID's of the controls in the CityX.aspx pages, then you will either need a way for those ID's to be discovered, or you will need to go through all controls within the iframe looking for the correct one. (I say this because if the controls in the iframe pages are held in any sort of ASP.NET structure they will not be called txtMyCtrl (for instance) but possibly something like ct00_txtMyCtrl.)
If you don't know the EXACT control name (because of the ASP.NET structure I mentioned before), you could do something like:
var frame = document.getElementById('myIFrame');
var ctrls = frame.document.getElementByTagName("INPUT");
for(var i=0;i<ctrls.length;i++){
if(ctrls[i].getAttribute("type")=="hidden" && ctrls[i].id.indexOf("_myControl") != -1){
ctrls[i].value = "New Value";
break;
}
}
Or if you have the ability to update the CityX.aspx pages, then you could have the following in the CityX.aspx page:
function getCtrls(){
return [document.getElementById("<%=hiddenCtrl.ClientID%>"),
document.getElementById("<%=anotherHiddenCtrl.ClientID%>")];
}
... and then in your parent page, something like:
var frame = document.getElementById('myIFrame');
var ctrls = frame.document.getCtrls();
for(var i=0;i<ctrls.length;i++){
ctrls[i].value = "New Value";
}
They're just ideas on a general theme

Saving webControls in the Session object

I have a panel (pnlPanel) with lots of controls like Textboxes and DropDownLists. I want them to be persistent when the user gets back to the page, so i tried this:
/*i have saved the panel like this
Session["testPanel"] = pnlTest;
*/
protected void Page_Load(object sender, EventArgs e)
{
if (Session["testPanel"] != null)
{
panel = Session["testPanel"] as Panel;
}
}
But its not working. Is it possible? The reason why i want to do this is because overhead is not a problem, and i want to cut down on coding time.
I've never tried this myself, but this seems to me to be an extra-ordinarily bad idea. Without testing it, my guess would be that this will create a ton of ViewState problems. Even if you could maintain the ViewState, attempting to keep this control over multiple page loads would be dangerous at best.
My recommendation would be to have a common object that holds the properties of the panel you want and just build a method into one of the early events to prepopulate a new panel with those properties.
Without knowing the entire reason for doing something like this, you should have a look at output caching directives. You would be best served by pulling the content out of the panel and into a user control. Then setting output caching on control, using VaryByCustom so you can use the user name or some other unique identifier to separate by user.
http://msdn.microsoft.com/en-us/library/hdxfb6cy.aspx and
http://msdn.microsoft.com/en-us/library/system.web.httpapplication.getvarybycustomstring.aspx
Using session and/or caching will be problematic if you are in a webfarm scenario. Cache is scoped to the application instance, so another server in the web farm will not have access to it.
Some other side effects of something like this include issues with viewstate.
What you try to do here is to cache the Panel but this is not the way. The panel as you save it is a running object on the memory and can not be saved as it is. You need to convert it to html string and save and cache this string. So near the Panel you place a literal, then you render the Panel and save it on session, and then actually you display the text from this render.
if(Session["testPanel"] == null)
{
TextWriter stringWriter = new StringWriter();
HtmlTextWriter renderOnMe = new HtmlTextWriter(stringWriter);
// render and get the actually html of this dom tree
testPanel.RenderControl(renderOnMe);
// save it as cache
Session["testPanel"] = stringWriter.ToString();
}
// render the result on a literal
cLiteralID.Text = Session["testPanel"];
// hide the panel because I have render it on literal.
testPanel.Visible = false;
Need some tests as is it. I use some similar code for custom control and custom cache, never save on session this amount of data.
First Approach
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["panel"] != null)
{
panel = ViewState["panel"] as Panel;
}
}
In this approach your ViewState objects were different. You may be getting some null values once the ViewState["panel"] is given the control memory and the object is being accessed in the impression that the Session was Session["panel"]
Second Approach
Save the Complete panel HTML in database and access it on the form load by keeping the function under IsPostBack.
Now with the continuity of approach - 2 assign the value to your session object.
this.Controls.Add(new LiteralControl("Your HTML"));
Third Approach
You can use File system. Save the div in your file and access the file at runtime.
Hope this may help you.
EDIT - 1 => Added code for second approach
I had a similar problem. I tried to save an object to the View State that stored a Panel and I got an error message telling me that Panels aren't serializable. You could try using a SerializationSurrogate.
https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate(v=vs.110).aspx

asp.net textbox dynamic creation with .CssClass attribute

I am having a scenario by which I have to dynamically create the form based on the user selection. In the form, there are few textboxes which should be added at the end to the Total Textbox.
The way I am distinguishing the textboxes to be added at the end is by specifying as below..
TextBox txt1 = new TextBox();
txt1.ID = "txt1";
txt1.CssClass = "addToTotal";
TextBox txt2 = new TextBox();
txt2.ID = "txt2";
txt2.CssClass = "addToTotal";
TextBox txt3 = new TextBox();
txt3.ID = "txt3";
txt3.CssClass = "txtTotalPoints";
PlaceHolder1.Controls.Add(txt1);
PlaceHolder1.Controls.Add(txt2);
PlaceHolder1.Controls.Add(txt3);
In reality, there is no css class named 'addToTotal' in the site css file. It's just used as a flag to notify me for adding at the end.
Is it a good practice to add a .CssClass even though the actual class does not exist. Are there any pitfalls in using this methodology?
I would assume that the overhead of using a CSS class which does not exist as a marker is minimal, so I wouldn't change your implementation based on that. If you're concerned about best practices - which you could rightly be, CSS classes were never intended to be used like this - you could add a data-* attribute to the input and use that instead:
txt2.Attributes["data-addToTotal"] = "true";
...then finding those elements with JQuery:
$("input[data-addToTotal='true']")
data-* attributes are part of HTML5, but are fully backwards compatible.

Categories