I created an application which has a menu where it's items are created dynamicly. The menu acts as a language menu.
<body runat="server">
<form id="Form1" runat="server">
<table class="TableLayout">
<tr>
<td class="TopNav" align="right">
<asp:Menu runat="server" ID="LanguageMenu" Orientation="Horizontal" OnMenuItemClick="LanguageMenu_MenuItemClick">
<LevelMenuItemStyles>
<asp:MenuItemStyle CssClass="TopNavItem" />
</LevelMenuItemStyles>
<StaticHoverStyle CssClass="TopNavItemHover" />
</asp:Menu>
</td>
</tr>
...
I use session variables to set my current language.
however if I click on the menu to change the session variable:
public void LanguageMenu_MenuItemClick(Object sender, MenuEventArgs e)
{
Session["language"] = e.Item.Text;
}
The page reloads with the following code:
sportsPath = String.Format(#"{0}{1}\Sports\", xmlPath, Session["language"]);
//create LeftNavigation
string[] sports = Directory.GetFiles(sportsPath);
LeftNavigation.Items.Clear();
foreach (string sport in sports)
{
string text = sport.Replace(sportsPath, "").Replace(".xml", "");
MenuItem item = new MenuItem();
item.Text = text;
LeftNavigation.Items.Add(item);
}
The thing is the content doesn't change, only after I click on something else.
If I skip through my code after clicking on the menuItem I can see that it passes the code and it should change, however for some reason the page needs another extra trigger to modify it's content.
I also see the page reloading so I don't understand why it's not changing immediatly. I guess I'm not understanding the asp.net logic just quite yet.
What am I doing wrong?
The Page_Load is triggered before the MenuItemClick event, thus causing your Session variable to be set after your page is updated.
To solve this, you could move your code in the Page_Load to the Page_PreRender event handler, which is fired after the MenuItemClick.
The solution to this is to Redirect the User to the same page after updating the language preference in Session.
public void LanguageMenu_MenuItemClick(Object sender, MenuEventArgs e)
{
Session["language"] = e.Item.Text;
Response.Redirct("samepage.aspx");
Response.End();
}
Related
I'm using an aspx file as my main page with the following code snippet:
<input type="text" runat="server" id="Password" />
<asp:Button runat="server" id="SavePassword"
Text="Save" OnClick="SavePassword_Click"/>
Then in the code behind I use:
protected void SavePassword_Click(object sender, EventArgs e)
{
string a = Password.Value.ToString();
}
Setting Password.Value in the Page_Load works as expected, but setting a to the value results in an empty string in a regardless what I type in on the page befoere I click the save button.
Am I overlooking here something?
You should add label field with name labelShow in aspx page like this
<asp:Label ID="labelShow" runat="server"></asp:Label>
Then add the string into .cs file
protected void SavePassword_Click(object sender, EventArgs e)
{
string a = Password.Value.ToString();
labelShow.Text = a.ToString();
}
I can figure several errors :
You say something about Page_Load. You should always remember Page_Load is executed at every postback. So if you write something into the textbox at Page_Load, it will erase the value typed by user. You can change this behavior by veriyfing
if(!IsPostBack)
{
// Your code
}
around your Page_Load content.
input runat="server" is not the proper way to do TextBox in ASP.Net, in most cases you should use asp:TextBox
You don't do anything with your "a" string, your current code sample does nothing, whether the Password field is properly posted or not. You can do as suggested by Ravi in his answer to display it.
I suggest you to to learn how to use VS debugger, and to read a good course on ASP.Net Webforms to learn it.
I'm trying to solve this problem.
I have an Accordion inside an UpdatePanel. Inside the Accordion control I dinamically create at most four AccordionPanes, each with a custom ListView that shows some image previews fetched from a database. Each preview is composed by a 160x120 ImageButton. When the user clicks on one of these buttons a popup is opened with the image at real size (by a Seadragon control); he can now rotate the image and save it back to the database. Now, after saving the image, I close the popup and submit a postback by generating a click event on a hidden button inside the UpdatePanel containing the Accordion, but even if I can step through the hidden button event code, the refresh doesn't take place. The hidden button was the last (and most effective) solution I've tried, without success. What am I missing ? (The absolute best solution would be refresh the only image that changed, because sometimes the ListView contains several previews).
This is the
<div>
<table class="style8">
<tr>
<td class="style2">
<asp:UpdatePanel ID="usersPanel" runat="server" >
<ContentTemplate>
<cc1:c1treeview ID="tvUsers" runat="server"
onselectednodeschanged="tvUsers_SelectedNodesChanged" AutoPostBack="True"
onnodecheckchanged="tvUsers_SelectedNodesChanged">
</cc1:c1treeview>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel ID="imagesPanel" runat="server" UpdateMode="Always" >
<ContentTemplate>
<asp:Button ID="hiddenImageRefresh" runat="server" Text="Refresh"
style="display:none;" onclick="hiddenImageRefresh_Click" />
<ajaxToolkit:Accordion ID="accImages" runat="server" >
</ajaxToolkit:Accordion>
</ContentTemplate>
</asp:UpdatePanel>
</td>
</tr>
</table>
</div>
And this is the code contained in the hidden button click event, code, that regularly runs when the popup closes. It simply extracts a user code (promo) and rebind the data (LoadImages)
protected void hiddenImageRefresh_Click(object sender, EventArgs e)
{
string promo = "";
if(Session[SessionVariables.CurrentPromoter] != null)
promo = Session[SessionVariables.CurrentPromoter].ToString();
LoadImages(promo, ddlImageType.SelectedValue);
}
Steps to refresh only updated image
Step#1: in JavaScript
//Take one global variable
var selectedImageId="";
Step#2: in JavaScript
//set above var with image id, When user clicks on the ImageButton, which is inside openPopup function
selectedImageId = this.id;
Step#3: in Code-Behind
protected void bSave_Click(object sender, EventArgs e) {
//SaveImage();
#region here get the imageUrl that needs to be updated and send as parameter in closePopup js function
var timeStamp = dImgTag.ToString("yyyyMMdd HH:mm:ss.fff") ;
var promoter = riga["PROMOTER"].ToString();
var pv = riga["PV"].ToString();
var imageUrl = string.Format("../Handlers/ImageLoader.ashx?id={0}&promo={1}&pv={2}", timeStamp, promoter, pv);
#endregion
ClientScriptManager csm = Page.ClientScript;
csm.RegisterStartupScript(Page.GetType(), "closeScript", "closePopup(true,'"+ imageUrl +"');", true);
}
Step#4: in JavaScript
function closePopup(refreshParent, imageUrl) {
if (refreshParent) {
//get the selectedImage and set the source with new url
var selectedImage = window.opener.document.getElementById(selectedImageId);
selectedImage.src = imageUrl;
}
window.close();
}
See below image first.
we have one sidebar navigation(ajax accordion control asp.net)
now when ever user click on link inside side bar related page(content) should display in Content goes here region.
As per given instruction entire page should not be refreshed or in other word in Back Button should not work(In Internet Explorer).
what should be the way to achieve this functionality?
what should be the best suggestion for that?
EDIT: navigation tree is inside MasterPage and Content goes region is in side content page of master page
please suggest me.....
thank you so much....
The Easiest way is to Wrap your side navigation & the Content placeholder in an UpdatePanel. Set the TreeView in the side bar as the UpdateTrigger for the update Panel. But, this approach is a little inefficient.
A slightly better way is ti just wrap the Content Placeholder in an Update Panel, along with a HiddenField in it. Upon a selection in the sidebar, update the HiddenField Value with JavaScript and then refresh the update Panel.
According to:
As per given instruction entire page should not be refreshed or in other word in Back Button should not work(In Internet Explorer).
And
sidebar tree view is in master page and Content goes here region is content page
If my understanding is correct, I think you do not need to place your TreeView control in your master page because you only want one page loading dynamically the content based on the selection of your tree view. So...Why is this important? Well if you place your tree view in your page you can use an UpdatePanel to avoid full posts.
Output of the following code
The following code covers the next points:
A TreeView control is embedded in a UserControl and placed in an ASPX page (left side)
The menu contorl exposes an event that is raised whenever the selected node changes, this event is handled in the ASPX page to dynamically load user controls depending on the user selection on the right side of the page, only one content is loaded at a time.
The controls are embedded in an UpdatePanel therefore you won't change your page and your back button in your browser won't be affected
Note: the user controls keep their state across post backs
(I'm not sure if this is the best way to do it, perhaps you could try to find a solution using only ajax, and avoid the use of the evil updata panels, but certainly this is a way to do it)
I'll try to simplify the code to reduce the size of the post, I will just post the code of one user control, the other one is exactly the same I just changed its title to difference them on the page
ASCX Menu
<asp:TreeView ID="TreeView1" runat="server" onselectednodechanged="Unnamed2_SelectedNodeChanged">
<Nodes>
<asp:TreeNode Text="link1" />
<asp:TreeNode Text="link2" />
</Nodes>
<SelectedNodeStyle Font-Bold="True" Font-Italic="True" />
</asp:TreeView>
ASCX Menu code behind
public event Action<string> MenuChanged = delegate { };
protected void Unnamed2_SelectedNodeChanged(object sender, EventArgs e)
{
this.MenuChanged(this.TreeView1.SelectedNode.Text);
}
ASPX
<asp:ScriptManager runat="server" ID="sm" />
<asp:UpdatePanel runat="server" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:HiddenField runat="server" ID="currentControl" />
<table border="0" cellpadding="0" cellspacing="0" width="90%" align="center">
<tr>
<td style="width:50%; background-color: Silver">
<menu:TreeViewMenu runat="server" ID="myTreeViewMenu" OnMenuChanged="myTreeViewMenu_MenuChanged" />
</td>
<td style="width:50%; background-color: Aqua">
<p>Result:</p>
<asp:Panel runat="server" ID="myPanel">
</asp:Panel>
<asp:Label ID="lblMessage" runat="server" />
</td>
</tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>
ASPX code behind
protected void Page_Init(object sender, EventArgs e)
{
if (this.IsPostBack)
{
var cc = this.Request.Form["currentControl"];
if (!string.IsNullOrWhiteSpace(cc))
{
var uc = this.LoadControl(this.Server.HtmlDecode(cc));
this.myPanel.Controls.Add(uc);
}
}
}
protected void myTreeViewMenu_MenuChanged(string e)
{
this.myPanel.Controls.Clear();
switch (e)
{
case "link1":
var cc1 = "~/Content1.ascx";
this.currentControl.Value = this.Server.HtmlEncode(cc1);
var uc1 = this.LoadControl(cc1);
this.myPanel.Controls.Add(uc1);
this.lblMessage.Text = "Updated from: link1";
break;
case "link2":
var cc2 = "~/Content2.ascx";
this.currentControl.Value = this.Server.HtmlEncode(cc2);
var uc2 = this.LoadControl(cc2);
this.myPanel.Controls.Add(uc2);
this.lblMessage.Text = "Updated from: link2";
break;
default:
this.lblMessage.Text = "Updated from default: " + e;
break;
}
}
ASCX
<h1>Content 1</h1>
<asp:TextBox runat="server" ID="txt" />
<asp:Button Text="Process data..." runat="server" OnClick="button_Click" />
<asp:Button Text="Just post" runat="server" />
<asp:Label ID="lblMessage" runat="server" />
ASCX Code Behind
protected void button_Click(object sender, EventArgs e)
{
this.lblMessage.Text = this.txt.Text;
}
You can simply copy-paste this code to test it yourself, this should work
Jupaol's answer works fine but 1 thing need to mention, I came across the problem after implemented Jupaol's idea, the first time I called the user control immediately after I click menu, the button with in the ascx works fine, but if I switch to 2nd one, first click of the button on the 2nd control will not fire on first click, this is because we do not have a "static" ID of the control. It took me almost 3 days to finally figure out why this is happening. so here's part of my code to make. I'm leaving this message in hope that anyone who read this afterwards will make the use of it.
if (!string.IsNullOrEmpty(controlPath))
{
PlaceHolder1.Controls.Clear();
UserControl uc = (UserControl)LoadControl(controlPath);
/**note below LastLoadedControl is anything that could
* be unique to the called control so every time when call back
* it will not confuse the back end so the first fire of eg. a button
* on that loaded control will work
*/
uc.ID = LastLoadedControl;
PlaceHolder1.Controls.Add(uc);
}
I'll also need to thank Jupaol's great contribution so that I can get my site running.
In a user control, I've got a Repeater inside of an UpdatePanel (which id displayed inside of a ModalPopupExtender. The Repeater is databound using an array list of MyDTO objects. There are two buttons for each Item in the list. Upon binding the ImageURL and CommandArgument are set.
This code works fine the first time around but the CommandArgument is wrong thereafter. It seems like the display is updated correctly but the DTO isn't and the CommandArgument sent is the one that has just been removed.
Can anybody spot any problems with the code?
Edit : I've just added a CollapsiblePanelExtender to the code. When I now delete an item and expand the panel, the item that was previously deleted (and gone from the display) has come back. It seems that the Repeater hasn't been rebuilt correctly under the bonnet.
ASCX
<asp:UpdatePanel ID="ViewDataDetail" runat="server" ChildrenAsTriggers="true">
<Triggers>
<asp:PostBackTrigger ControlID="ViewDataCloseButton" />
<asp:AsyncPostBackTrigger ControlID="DataRepeater" />
</Triggers>
<ContentTemplate>
<table width="100%" id="DataResults">
<asp:Repeater ID="DataRepeater" runat="server" OnItemCommand="DataRepeater_ItemCommand" OnItemDataBound="DataRepeater_ItemDataBound">
<HeaderTemplate>
<tr>
<th><b>Name</b></th>
<th><b> </b></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<b><%#((MyDTO)Container.DataItem).Name%></b>
</td>
<td>
<asp:ImageButton CausesValidation="false" ID="DeleteData" CommandName="Delete" runat="server" />
<asp:ImageButton CausesValidation="false" ID="RunData" CommandName="Run" runat="server" />
</td>
</tr>
<tr>
<td colspan="2">
<table>
<tr>
<td>Description : </td>
<td><%#((MyDTO)Container.DataItem).Description%></td>
</tr>
<tr>
<td>Search Text : </td>
<td><%#((MyDTO)Container.DataItem).Text%></td>
</tr>
</table>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</ContentTemplate>
</asp:UpdatePanel>
Code-Behind
public DeleteData DeleteDataDelegate;
public RetrieveData PopulateDataDelegate;
public delegate ArrayList RetrieveData();
public delegate void DeleteData(String sData);
protected void Page_Load(object sender, EventArgs e)
{
//load the initial data..
if (!Page.IsPostBack)
{
if (PopulateDataDelegate != null)
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
}
}
protected void DataRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
if (DeleteDataDelegate != null)
{
DeleteDataDelegate((String)e.CommandArgument);
BindDataToRepeater();
}
}
else if (e.CommandName == "Run")
{
String sRunning = (String)e.CommandArgument;
this.ViewDataModalPopupExtender.Hide();
}
}
protected void DataRepeater_ItemDataBound(object source, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
if (item != null && item.DataItem != null)
{
MyDTO oQuery = (MyDTO)item.DataItem;
ImageButton oDeleteControl = (ImageButton) item.FindControl("DeleteData");
ImageButton oRunControl = (ImageButton)item.FindControl("RunData");
if (oDeleteControl != null && oRunControl !=null)
{
oRunControl.ImageUrl = "button_expand.gif";
oRunControl.CommandArgument = "MyID";
if (oQuery !=null)
{
//do something
}
oDeleteControl.ImageUrl = "btn_remove.gif";
oDeleteControl.CommandArgument = "MyID";
}
}
}
public void BindDataToRepeater()
{
this.DataRepeater.DataSource = this.PopulateDataDelegate();
this.DataRepeater.DataBind();
}
public void ShowModal(object sender, EventArgs e)
{
BindDataToRepeater();
this.ViewDataModalPopupExtender.Show();
}
Thanks for reminding me why I stopped using ASP.NET controls. This is the exact type of nightmare that has made too many projects go way over budget and schedule.
My advise to you is to think of the simplest way to implement this. You can try to bend over backwards in order to get this to work the ASP.NET way or take the shortest route.
All you're doing is generating HTML, it should never be that difficult.
The most likely cause of your problem is that the ViewState is stored in the page which doesn't get updated on a partial postback. So with every change in the update panel you'll postback the initial viewstate of the page.
Try replacing the repeater with a simple for-loop (and ignore the people who start complaining you shouldn't mix markup and code). Replace your databinding statements with <%= %>.
That eliminates the view state all together and should remove any removed row from re-appearing.
After many days of messing around with this I've not found a proper fix for the problem but do have a workable work-around.
The CollapsiblePanelExtender is set to NOT postback automatically which fixes the issue of the deleted data re-appearing when the extender is opened. The other issue, I believe, is related.
It seems that the ViewState for the Repeater is out of sync with the data. e.CommandArgument is not always correct and seems to reference the previous data. I made an attempt to fix it by storing the ArrayList of MyDTO objects in the ViewState when opening the Modal dialog and using the ID retrieved from e.Item.ItemIndex to find the correct element to delete. This didn't work correctly, the ArrayList pulled out of the ViewState was out of sync.
Storing the ArrayList in the session makes it all work which leads me to believe that I'm doing something fundamentally wrong or there is a subtle bug in the version of the toolkit that i'm using (we're still on VS2005 so are stuck with an older version of the toolkit)
Apologies if this makes no sense, contact me if you want clarification on anything.
try using
((IDataItemContainer)Container).DataItem
instead of "Container.DataItem"
It worked for me.
I have an ASP.NET page that has two input elements:
A TextBox that is ReadOnly. This TextBox is the TargetControl of a CalendarExtender
A DropDownList with AutoPostBack=true
Here is the code:
<table border="0" cellpadding="0" cellspacing="0">
<tr><td colspan="2">Date:</td></tr>
<tr><td colspan="2">
<asp:TextBox ID="dateTextBox" runat="server" ReadOnly="true" />
<ajax:CalendarExtender ID="datePicker" runat="server" Format="MM/dd/yyyy" OnLoad="datePicker_Load" TargetControlID="dateTextBox" />
</td></tr>
<tr><td colspan="2">Select an Option:</td></tr>
<tr>
<td>Name: </td>
<td><asp:DropDownList ID="optionsDropDownList" runat="server" AutoPostBack="true"
OnLoad="optionsDropDownList_Load"
OnSelectedIndexChanged="optionsDropDownList_SelectedIndexChanged"
DataTextField="Name" DataValueField="ID" />
</td></tr>
<tr><td><asp:Button ID="saveButton" runat="server" Text="Save" OnClick="saveButton_Click" /></td></tr>
</table>
When the DropDownList posts back, the date selected by the user with the datePicker is reset to the current date. In addition, if I look at the Text property of dateTextBox, it is equal to string.Empty.
How do I preserve the date that the user selected on a PostBack?
Certainly you must do as others have already suggested: set readonly field dynamically rather than in markup, and make sure you are not accidentally resetting the value in Page_Load() during postbacks...
...but you must also do the following inside Page_Load(), because the CalendarExtender object has an internal copy of the date that must be forcibly changed:
if (IsPostBack) // do this ONLY during postbacks
{
if (Request[txtDate.UniqueID] != null)
{
if (Request[txtDate.UniqueID].Length > 0)
{
txtDate.Text = Request[txtDate.UniqueID];
txtDateExtender.SelectedDate = DateTime.Parse(Request[txtDate.UniqueID]);
}
}
}
The fact that the text box is read only appears to be causing this problem. I duplicated your problem using no code in any of the bound events, and the date still disappeared. However, when I changed the text box to ReadOnly=False, it worked fine. Do you need to have the textbox be read only, or can you disable it or validate the date being entered?
EDIT: OK, I have an answer for you. According to this forum question, read only controls are not posted back to the server. So, when you do a postback you will lose the value in a read only control. You will need to not make the control read only.
protected void Page_Load(object sender, EventArgs e)
{
txt_sdate.Text = Request[txt_sdate.UniqueID];
}
If you want the textbox contents remembered after the postback and still keep it as readonly control, then you have to remove the readonly attribute from the markup, and add this in the codebehind pageload:
protected void Page_Load(object sender, EventArgs e){
TextBox1.Attributes.Add("readonly", "readonly");
// ...
}
The solution to the issue is making use of Request.Form collections. As this collection has values of all fields that are posted back to the server and also it has the values that are set using client side scripts like JavaScript.
Thus we need to do a small change in the way we are fetching the value server side.
C#
protected void Submit(object sender, EventArgs e)
{
string date = Request.Form[txtDate.UniqueID];
}
I suspect your datePicker_Load is setting something and not checking if it's in a postback. That would make it happen every time and look like it was 'resetting'.
In stead of setting ReadOnly="False", set Enabled="False". This should fix your issue.
#taeda's answer worked for me. FYI, if someone uses enabled = "false" instead of readonly = "true" wont be able to use that answer, because Request[TxtDate.UniqueId] will throw a null exception.
It is not a problem of Preserving,after setting readonly = true the value of the particular textbox doesn't be returned back to server
so
Use contentEditable="false" and made readonly = false
that would prevent value is being entered other than Calendar Extender selection also returns the value of the Text box back to the server