I use RadTreeView in my master page :
but i face the following problem :
I lose my selections when i click on the nodes of the tree view .and every time i click on the node it makes (Response.Redirect("...")) which make the master entering the (!Page.IsPostback)
every time and bind the tree view again so i lose my selections .
How to fix this problem .
My .aspx :
<telerik:RadTreeView ID="rtv_cm" runat="server" OnNodeExpand="rtv_cm_NodeExpand"
OnNodeClick="rtv_cm_NodeClick" Skin="WebBlue">
</telerik:RadTreeView>
My .cs :
protected void Page_Load(object sender, EventArgs e)
{
if (Session["emp_num"] != null && !string.IsNullOrEmpty(Session["emp_num"].ToString()))
{
if (!Page.IsPostBack)
{
LoadRootNodes(rtv_cm, TreeNodeExpandMode.ServerSide);
}
}
else
{
Response.Redirect("Frm_login.aspx");
}
}
protected void rtv_cm_NodeClick(object sender, RadTreeNodeEventArgs e)
{
dt_childs = (DataTable)Session["dt_childs"];
IEnumerable<DataRow> result = from myRow in dt_childs.AsEnumerable()
where myRow.Field<string>("task_id").TrimEnd() == e.Node.Value.TrimEnd()
select myRow;
if (result != null)
{
if (!string.IsNullOrEmpty(result.ElementAtOrDefault(0).Field<string>("page_name")))
{
Response.Redirect(result.ElementAtOrDefault(0).Field<string>("page_name").TrimEnd(), false);
}
}
}
How I get The menu :
private void LoadRootNodes(RadTreeView treeView, TreeNodeExpandMode expandMode)
{
dt = Menu_db.GetMenu(Session["emp_num"].ToString(), CMSession.Current.db_code);
IEnumerable<DataRow> result = from myRow in dt.AsEnumerable()
where myRow.Field<string>("task_id").TrimEnd() == "0"
select myRow;
if (result != null && result.Count()>0)
{
DataTable dt_roots = result.CopyToDataTable<DataRow>();
Session["dt"] = dt;
Session["dt_roots"] = dt_roots;
foreach (DataRow row in dt_roots.Rows)
{
RadTreeNode node = new RadTreeNode();
node.Text = row["task_name"].ToString().TrimEnd();
node.Value = row["task_id"].ToString().TrimEnd();
if (Convert.ToInt32(row["count"]) > 0)
{
node.ExpandMode = expandMode;
}
treeView.Nodes.Add(node);
}
}
}
HTTP is what's known as a "stateless protocol". Basically, it's as if the server has a severe case of Alzheimer's disease (no disrespect intended). The server answers your query, but then forgets you were ever there.
When HTTP was used primarily for fetching static documents, this posed no problem, but web applications require some kind of state. There are many ways this is accomplished, but ASP.NET typically makes heavy use of the "ViewState". The view state is simply an <input type="hidden"> tag which contains base-64 formatted byte code. (If you view the source of your rendered HTML page in the browser, you see it - named "__VIEWSTATE"). When the user resubmits the form (by clicking a button, etc), the viewstate data is sent back to server. Basically, it's like reminding the server about what it told you last time. This is how TextBoxes and GridViews are able to seemingly maintain their state between postbacks - they store their state in the "viewstate".
The problem with the viewstate, though, is that it can be easily lost. You must submit the form or the viewstate will not be persisted. If you use an anchor tag or Request.Redirect, you are side-stepping the form and hitting a web page all on your own and, in the process, you are not passing any of the viewstate along.
There is often no way to avoid this, so there are other ways to store your application's state. But, unlike the viewstate, this is something you must do manually for each and every value that you want to persist. You can store the data in a cookie, you can store the data on the server (using Server["key"] or Session["key"]) or you can persist the data in something more concrete, like a database or a text file. All of this must be done manually, however, and then you must reload the data when you reload the page.
In your case, you may want to guess which item was selected based on the current page (since the treeview items and pages seem to be linked) and set the selected item explicitly. If that's not feasible, you could try storing the selected item in the Session, using something like Session["Master_SelectedTreeViewItem"] = treeViewItem.Id;. Then, in Page_Load, get this value (careful, it may be null) and then set the corresponding treeview item as selected.
I would post more code examples, but you haven't provided the code where you are loading the treeview, etc, so it would be difficult to do.
Further Info
ASP.NET State Management Overview (MSDN)
The only way i can think of is storing the selection in session and on (!Page.IsPostBack), look for that Session key and update your selection after the binding.
The problem you face is because essentially, trough your Redirect, you go to a different html page, so ViewState is out the window, nevermind that it is the same address.
If you are binding the tree with urls that link to other page, append the selection using query string, then load the tree selection from the query string from the other page.
If you think that the second page you are redirecting to has same UI as the first, dont redirect instead load it on the same page with the new content for the selection, this will allow you to maintain the state in asp.net if the control supports view state.
I already had this problem, exactly same problem, needs to redirect on TreeViewItemClick.
I solve it storing the last selected item is session, and selection it again on page load.
Somethink like this
protected void rtv_cm_NodeClick(object sender, RadTreeNodeEventArgs e)
{
Session["LastClickedNode"] = e.Node.Value;
...
}
and in your Load method, verifi ir the node needs to be selected, like this.
private void LoadRootNodes(RadTreeView treeView, TreeNodeExpandMode expandMode)
{
//... your code
if (Session["LastClickedNode"] !=null)
{
if (row["task_id"].ToString().TrimEnd() == Session["LastClickedNode"].ToString())
{
node.Selected = true;
}
}
}
i think this will solve your problem.
Related
I have a web form in .NET using ASP and C#. This form has a DropDownList control with its AutoPostBack property set to True.
Some data on the form is displayed when the user selects an item from the DropDownList.
Now, I want the user to be able to share his or her data by just copying the URL which has the QueryString on it like http://www.site.com?ProdID=1234.
I have done the following to try to accomplish this:
protected void Page_Load(object sender, EventArgs e)
{
// check if the URL has a QueryString item if yes the use it.
if (!String.IsNullOrEmpty(Request.QueryString["ProdID"]))
{
ddlProduct.SelectedIndex = ddlProduct.Items.IndexOf(ddlProduct.Items.FindByValue(Request.QueryString["ProdID"]));
}
}
The Problem with this code is that when the user chooses a different item from the DropDownList his or her selected item gets overwritten by the Page_Load() since we have now a QueryString on the URL. (I build the QueryString and then use the Redirect() method to the same page on an Event)
So my question here is: Is it possible to keep changing the URL's query string on the fly when the user changes the selected item from the DropDownList and display the proper data on the form for the selected item?
I have the feeling that this is like the chicken or the egg problem.
Thank you.
Check for whether or not the page is posting back to the server, along with your existing logic, like this:
if(!IsPostBack && !String.IsNullOrEmpty(Request.QueryString["ProdID"]))
{
ddlProduct.SelectedIndex = ddlProduct.Items.IndexOf(ddlProduct.Items.FindByValue(Request.QueryString["ProdID"]));
}
I've just developed a new GridView MultiFilter control ( CompositeControl ) that works like the image below:
I use ViewState for my control's properties so it keeps all values after postback. I want to save my control properties to a Session before redirect so I can load properties back to my control when my page loads again.
Does anyone have any suggestions about how this can be accomplished?
You have to do 2 things in this list page:
(1)Page load
(2)Search click
And 1 thing in detail (redirected) page:
(3)Pass some query string while back to list page
(1)while page load decide to load normal or searched (back from detail page) data
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if (Request.QueryString["back"] != null)
bindDataFirst();
// same data load logic as present
else
bindDataForBack();
// you come back from detail page hence bind search & grid data
}
private void bindDataForBack()
{
strName = Session["SearchName"] == null ? "" : Session["SearchName"].ToString();
// check session search conditions & data and bind
//also bind grid by respective search parameters & search options (top side)
(2)search click store search data into session
public void btnSearch_Click(object sender, System.EventArgs e)
{
Session["SearchName"] = strName;// store search data into session variables
//bind grid by respective search parameters
(3)in redirected (detail) page set back button like:
public void btnBack_Click(object sender, System.EventArgs e)
{
Response.Redirect("ListPage.aspx?back=1");
I hope this may helps you. I suggest to implement this with one textbox & grid and then try with your present scenario.
Please mark this answer useful if this solve your problem.
You can assign data to Session the pretty much the same way you assign to ViewState.
It's a key value dictionary just like ViewState.
Ex:
Session["someKey"] = "An arbitrary value";
If you can redirect to another page using form submit then You can post your form to the required page using action attribute of your page. This way values of all controls will be available in the Request["KEY NAME HERE"]
<form action="anotherpage.aspx" id="frmData">
<!-- YOUR CONTROLS HERE -->
<input type="submit" value="Submit" />
</fomr>
you can also submit your form using JS
$("#frmData").submit();
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
I have a simple ListView paged by a DataPager giving a list of products. When we click on the product we open the product details page. On the details page we want to "return to product list" but of course we want it to remember what page the datapager was at.
Surely this was conceived as a natural design requirement - what is the simple out-of-the-box way to do this?
If we use the QueryStringField property of DataPager we get the page number in the URL so I hoped I could use the referrer URL in the back link, but I have found the Request.UrlReferrer to be unreliable (when I use F5 to debug the app in Internet Explorer for example, Request.UrlReferrer is always null).
I have found some success with storing the page number in a session variable:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if (Session["PagerIndex"] != null)
{
DataPager1.SetPageProperties((int)Session["PagerIndex"],
DataPager1.MaximumRows, false);
}
}
}
protected void DataPager1_PreRender(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
Session["PagerIndex"] = DataPager1.StartRowIndex;
}
}
This method has some drawbacks:
Only works if QueryStringField is blank (so IsPostBack can be detected)
Session/cookie variable required for each pager
Question of how to reset the session/cookie variables arises
What is the "proper" way to do this?
Thanks
You can try my solution
Set the QueryStringField property of your datapager to a querystringfield say page.
<asp:DataPager ID="DataPager2" runat="server" PagedControlID="ListView1"
QueryStringField="page">
....
Note: I placed the DataPager outside of the ListView.
Put linkButton in your listview that will redirect you to detailspage and in its click event save the current page number in a Session
int integ;
decimal fract;
integ = DataPager2.StartRowIndex / DataPager2.PageSize;
fract = (DataPager2.StartRowIndex / DataPager2.PageSize) - integ;
if (fract > 0)
page = integ;
else if (integ > 0) page = integ - 1;
Session["page"]=page;
On the details page retrieve the page and pass back as a querystring to ListViewpage.
Automatically the datapager will take you to that page number, if not specified to page number 1.
Good Luck !
If you don't have any filters you can simply recalculate the page on which the product was.
Another option will be to encode the page (together with possible filter values for the list) in the URL of the product detail page and use them to generate an URL for the list that will be essentially the same as the one of the original list. Even something like the ReturnUrl approach used for login. Sharepoint does similar thing with its lists but I feel the URL can get too messy (and I am not a person that falls for the whole "clean URL" bullshit when I say it is messy it really is)
One more option would be to pass the product ID to the list page via the URL. The list page can then calculate the appropriate page. This will remove the noise from the URLs
I have a website that returns search results from Twitter, written in C# ASP.NET. The search works very well.
When the user sees the results I want them to also have a 'Next Page' type hyperlink that will perform the search from the last previous result onwards (using Twitter's next_page data).
How can I preserve properties so that when a link is clicked it will run the search again with different parameters for the next results? I cannot use Form as there is one Form on the page already and MS limits to one Form per page (for runat="server").
Please help, this is driving me nuts.
PS I thought of including code, but not sure which bit to include, as it has more to do with how ASP.NET works as much as how my own coding is.
There's a hundred different ways to solve this problem. The ASP.NET infrastructure includes something called ViewState, which allows the page and its controls to persist arbitrary data and objects across page views.
There is a single <form>, but you can have an unlimited number of links and buttons which submit the form in different ways - each one can trigger its own method when the page posts back.
A simple way to leverage this in your case is to store the page parameter on the "next page" link. This is a very simple example that assumes you only need to know the page number, but it gets the point across:
<asp:LinkButton runat="server" ID="next_page" Text="Next Page" OnClick="NextPage_Click" />
...
void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
LoadData(0);
}
}
void LoadData(int page)
{
//pull page of data from twitter & show on page
next_page.CommandArgument = (page+1).ToString();
}
void NextPage_Click(object sender, EventArgs e)
{
int page = int.Parse(((LinkButton)sender).CommandArgument);
LoadData(page);
}
In this example we set the CommandArgument property of the LinkButton to the page index we want. The LinkButton triggers the NextPage_Click method to be called, and ASP.NET's ViewState infrastructure allows the CommandArgument value is persisted.
There are two easy ways to do it:
Include a parameter in the url that is the href of the Next hyperlink, the url could look something like this:
http://mysite.com/myWebPage.aspx?currentPage=1
you can then access that parameter from the querystring in your code behind.
You can also save it to Session:
Session["currentPage"] = 1;
then upon postback you can check for it:
int currentPage = 0;
if (Session["currentPage"] != null)
int.TryParse(Session["currentPage"].ToString(), out currentPage);
with the Session it will automatically expire depending on your IIS setup, whereas using the querystring option it doesn't expire (although the user can mess with it so you will have to validate it before using it).
Have your properties save their values to the viewstate.
Something like this:
public int PageNumber
{
get
{
object value == this.ViewState["PageNumber"];
if(value != null)
{
return (int)value;
}
else
{
return 1;
}
}
set
{
this.ViewState["PageNumber"] = value;
}
}