How to prevent asp.net page from reseting data table? - asp.net

Consider this code
DataTable dt = new DataTable() ;
protected void Page_Load(object sender, EventArgs e)
{
dt.Columns.Add("RowIndex");
dt.Columns.Add("FilterText");
}
I will Fill this data table by some data during executing program. but when i click a button , the page will reload the codes and my data will be lost.
how can i prevent the web form from creating new data table and save my data?
my controls are inside an update panel.

A new instance of the class is created for each request. If you want to save things from one request to another you need to use a different mechanism.
For example a global. But on top of a globals usual problems you need to handle multiple concurrent requests and thus multi-threading and locking.
The usual approach is to store persistent state in a database, loading the information for each request at the start of processing that request.

You can use View State to solve problem..
DataTable dt;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dt = new DataTable();
dt.Columns.Add("RowIndex");
dt.Columns.Add("FilterText");
}
else
{
if (ViewState["vsDT"] != null)
dt= ViewState["vsDT"] as DataTable;
}
}

Related

Why is my list empty when i try to read it

I am crating a web application in asp.net that has only textboxes and 2 buttons.
1 button to read from the textboxes and put into a list
2 button to read from the list and put it into TXT file
But when I try to read the list it shows as empty and just skips
This is the code:
{
public List<Artikal> lista = new List<Artikal>();
protected void Page_Load(object sender, EventArgs e)
{
}
public void Button1_Click(object sender, EventArgs e)
{
var novi = new Artikal(TextBox1.Text, TextBox2.Text, TextBox3.Text, TextBox4.Text, TextBox5.Text, TextBox6.Text, TextBox7.Text, TextBox8.Text, TextBox9.Text);
lista.Add(novi);
}
protected void Button2_Click(object sender, EventArgs e)
{
foreach (Artikal trenutan in lista)//This whole part is skiped bcs the lsit is empty
{
using (StreamWriter sw = new StreamWriter(Server.MapPath("OVAJFAJL.txt"), true))
{
sw.WriteLine(string.Format(trenutan.ispis()));
}
}
}
}
Web applications are state-less. What this means in this context is that every request to this server-side code results in a new instance of the page class.
So this is re-created on every request:
public List<Artikal> lista = new List<Artikal>();
If you want data to persist across requests, you have to persist it somewhere. Session state is a simple approach. Page state or some client-side data can be used where appropriate, but this like isn't one of those cases. A file is simple, but doesn't scale well in terms of race conditions and such. A database is ideal because it also persists across web application restarts, which can happen at any time really.
Basically, you have to save your data somewhere.

Adding multiple custom controls

I have a custom control (customContainer) that can hold multiple custom controls of type ConditionControl. When I click a button in my customContainer control I want to add another customControl to my container.
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
CustomControlsPanel.Controls.Add(new LiteralControl("<br />"));
ConditionControl myCc = (ConditionControl)LoadControl(#"~/ConditionControl.ascx");
CustomControlsPanel.Controls.Add(myCc);
}
This works only once. So I click it once, it adds a Condition control but then it does not work anymore. How can I fix this ?
Edit: I tried saving the control collection of my panel into a session variable and then using that in order to restore the controls like so:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Session["controls"] = ConditionControlsPanel.Controls;
}
else
{
ControlCollection temp = (ControlCollection)Session["controls"];
ConditionControlsPanel.Controls.Clear();
foreach (Control ctrl in temp)
{
ConditionControlsPanel.Controls.Add(ctrl);
}
}
}
I get an error when I try to add a new control saying Collection was modified; enumeration operation may not execute. when I try to do the foreach
That is because everytime you click on the button, it postbacks, removes the first one and adds the new one. To overcome this, you can either prevent postback(by something like UpdatePanel) or keep the count of the added ConditionControls (like in session) and add controls as many as the counter you keep in session says

When to fill a sorted asp:GridView?

i've tried to ask this question a number of ways. It's a difficult question to answer because you have to understand what's going on.
When do i fill a GridView?
The nieve answer is during Page_Load, if not a PostBack:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
The problem with that is that if it is a postback, the grid is not filled. The reason the grid is not filled is because we've turned off the viewstate of the grid.
So don't look at IsPostBack
We need to always fill the grid, postback or not:
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
The problem with that is that if the user sorts a column, the OnSorting event is called after both Page_Init and Page_Load:
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
DataSet ds = GetStuffToShow(e.SortExpression, e.SortDirection);
GridView1.DataSource = ds;
GridView1.DataBind();
}
we've run two database queries, when only one was required.
Cache is fine for column sorting
If i'm willing to accept invalid cache during column sorting, i can store the DataSet in the session variable, as long as i invalidate it for any other operation.
The problem is the OnSorting event is called after i need it (Page_Load):
protected void Page_Load(object sender, EventArgs e)
{
if (AGridViewOnSortingEventIsntBeingRaised)
{
DataSet ds = GetStuffToShow();
StoreTheDatasetInTheSessionSomehowInCaseTheyCallSortInTheFuture(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
DataSet ds = GetDataSetOutOfSessionSomehowThatDamnWellBetterBeThere();
SomehowSortAReadOnlyDisconnectedDataSet(ds, e.SortExpression, e.SortDirection);
GridView1.DataSource = ds;
GridView1.DataBind();
}
Fear of the unknown
Then there's still the terror i have because i turned off viewstate of the GridView. i don't think that a read-only asp:GridView should need tens of kilobytes base64 encoded, when i can just rebuild it from the server (or from memory).
But i believe that i am obligated to return the GridView to the state it was in the last time the page was rendered. And i have to do it before Page_Load (i.e. during Page_Init). i have this fear because someone said so. So i turn it into
protected void Page_Init(object sender, EventArgs e)
{
if (AGridViewOnSortingEventIsntBeingRaised)
{
DataSet ds = GetStuffToShow();
StoreTheDatasetInTheSessionSomehowInCaseTheyCallSortInTheFuture(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
}
The problem with this is that GetStuffToShow depends on things the user has typed into text boxes, which don't exist during Page_Init
Anyway, i'm rambling. It's too hot in here. Hopefully this question will be answered, unlike my other recent frustrations with asp.net
Bonus Reading
Sorting GridView Formed With Data Set
By adding a couple of hidden fields, one for the sort expression, and the other for the sort direction you can use those values to populate the GridView once at page load and then update the sorting in the Sorting event (sort code modified from the All-In-One Code Framework GridView sample):
protected void Page_Load(object sender, EventArgs e)
{
DataSet ds = GetStuffToShow();
GridView1.DataSource = ds;
GridView1.DataBind();
}
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
// If the sorting column is the same as the previous one,
// then change the sort order.
if (SortExpression.Value.Equals(e.SortExpression))
{
SortDirection.Value = SortDirection.Value.Equals("ASC") ? "DESC" : "ASC";
}
// If sorting column is another column,
// then specify the sort order to "Ascending".
else
{
SortExpression.Value = e.SortExpression;
SortDirection.Value = "ASC";
}
var sortedView = new DataView(<convert your DataSet to a DataTable>)
{ Sort = string.Format("{0} {1}", this.SortExpression.Value, this.SortDirection.Value) };
GridView1.DataSource = sortedView;
GridView1.DataBind();
}
Note that SortDirection and SortExpression are the hidden fields. This also lends itself well to caching the DataSet.
Also, I wouldn't be concerned about the Page_Init issue that you brought up. That should only apply if you are dynamically creating your Controls.
A simple solution is to call Gridview.DataBind() on the Page.Pre_Render event, which makes it called after having handled any Button/Sorting, events. This a good way to ensure you call it only once per Request.
To make things clearer, it is also a good thing to access your dataset through a Property which will basically call your "Store-The-Dataset-In-The-Session-Somehow-In-Case-They-Call-Sort-In-The-Future" method in its Set part and your "Get-Data-Set-Out-Of-Session-That-Had-Better-Be-There" in the Get part.
You may try to fill the grid on Gridview Needdatasource event
it will be called when ever you perform a postback and get the proper functionality what ever you code in the event.
also if you want to bind it again you can just data databind method and that will call the needdatasource event again

Fields not changing in Formview when moving Pagination

I have a formview that on page load makes a call to a sql server and retrieves 5 records which I want the formview to paginate though.
I have sucessfully connected to the db, filled a dataset, and returned data when the web page renders. The problem is that when I move to a new page, the data does not change in the databound field.
Here is my code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
conn = new SqlConnection(connstr);
ds = new DataSet();
da = new SqlDataAdapter("call to stored proc", conn);
try
{
conn.Open();
da.Fill(ds, "m");
FormView1.DataSource = ds;
FormView1.DataKeyNames = new string[] { "PropKey" };
FormView1.DataBind();
}
catch (Exception ex)
{
Result = ex.Message;
}
finally
{
conn.Close();
}
}
Next when the paginate buttons are clicked I have this:
protected void FormView1_PageIndexChanging1(object sender, FormViewPageEventArgs e)
{
FormView1.PageIndex = e.NewPageIndex;
}
Please help,
Thanks
You will need to bind the data to the FormView just after setting the new page index like below.
protected void FormView1_PageIndexChanging1(object sender, FormViewPageEventArgs e)
{
FormView1.PageIndex = e.NewPageIndex;
BindFormViewData();
}
This is required because the FormView only displays the data for the active record and does not store any other records from the datasource, so upon change of the page index, the datasource is required to be bound again. See: Paging in a FormView Web Server Control
From the above link:
If the FormView control is bound to a data source control, or to any
data structure that implements the ICollection interface (including
datasets), the control gets all the records from the data source,
displays the record for the current page, and discards the rest. When
the user moves to another page, the FormView control repeats the
process, displaying a different record.
Hope this helps.

how to insert data within a calendar cell into a database

i have a calender and i was able to add text-box inside the cell using the day-render event but what i am trying to do is allow the user to add data to the text-box and then press add and the content is added to a database and showed inside that same text-box:
here is what i did:
protected void Page_Load(object sender, EventArgs e)
{
Calendar1.SelectedDate = DateTime.Now;
}
protected void update(object sender, DayRenderEventArgs e)
{
TextBox tb = new TextBox();
Button1.click += new EventHandler(insert);
e.Cell.Controls.Add(Button1);
e.Cell.Controls.Add(textBox2);
}
protected void insert(object sender, EventArgs e)
{
}
and i know how to insert the data but i am lost on how to identify it and output it back to the same text box
thanks
Well I'm not sure exactly what part you are lost on based on your question, so short of providing a complete working example I'll hit some of the main points:
1) To identify the data you are inserting, attach a date (and time if applicable) to the record. (Edit: are you looking for a mechanism to accomplish this? If so post your current DayRender handler code and Calendar markup).
2) To populate individual day data in a calendar, use Calendar.VisibleDate (to filter DB results) in a Page.Load handler to load a data structure (such as a List<T>) with day data for the entire month. Then in a Calendar.DayRender handler, add appropriate records from the structure to the e.Cell.
3) To cause the new results to show up on the first page refresh after insertion, you should be able to get away with using a Response.Redirect to the current page after insertion. This will cause the page generation process to restart, but you will lose ViewState.
Edit: Here is a basic prototype of what I tried to describe above. Note that you could pre-fetch into any enumerable data type, I use a List<T> here.
//Page code-behind
public partial class Default2 : System.Web.UI.Page
{
List<DataObject> liCurrentMonth = new List<DataObject>();
protected void Page_Load(object sender, EventArgs e)
{
liCurrentMonth = DataObject.GetCurrentMonth(Calendar1.VisibleDate);
}
protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
foreach (DataObject item in liCurrentMonth)
{
if (item.date == e.Day.Date)
{
Literal lit = new Literal();
lit.Text = item.text;
e.Cell.Controls.Add(lit);
}
}
}
}
//Data layer object
public class DataObject
{
public DateTime date { get; set; }
public string text { get; set; }
public static List<DataObject> GetCurrentMonth(DateTime currentdate)
{
//Get items from the db here, based on currentdate parameter
//and populate the List<DataObject>.
return new List<DataObject>();
}
}
I'm not sure you'll get this to work. Its the page viewstate that remembers the value entered into textboxes etc. Viewstate is created just before the page renders. The Calendar DayRender event is called during the calendars rendering, and hence after viewstate has done its thing. Therefore the viewstate mechanism is not aware of the existance of the textboxes and so will not track their content.
Perhaps you could assign each textbox an ID based on the month and day number, on postback you could check for this control ID in the Request.Form collection and do something with the data?

Resources