C# asp.net why does my manual __doPostBack only run once? - c#

In my code I create the menu items dynamically:
string listClientID = BulletedList1.ClientID.Replace('_', '$');
int counter = 0;
foreach (DataRow dataRow in database.DataTable.Rows)
{
// Add Button
ListItem listItem = new ListItem();
listItem.Value = "buttonItem" + Convert.ToString(dataRow["rank"]);
listItem.Text = " " + Convert.ToString(dataRow["title"]);
listItem.Attributes.Add("onclick", "__doPostBack('" + listClientID + "', '"+ counter.ToString() +"')");
BulletedList1.Items.Add(listItem);
counter++;
}
This menu is inside a update panel:
<div id="MenuItemBox">
<asp:BulletedList
ID="BulletedList1"
runat="server"
OnClick="MenuItem_Click"
>
</asp:BulletedList>
</div>
What I want is when a listitem is clicked it performs a postback. But when I run this, the onclick event is only runned once.
For example. I have 4 listitems. When I click the first item the first time the onclick event is executed. Now I click the second item, the onclick event is also executed. But when I now click the first item again the onclick event is not fired.
When I check the error console in FireFox or Oprah I don't get any errors.
So my question is: how can I fix this and what am I doing wrong?

It seems you need to rebind it after postback.
Where do you add items to the menu and are you checking IsPostBack property?
Please compare html after first loading and postpack to see if _dopostback dissappear.
Then Try to remove IsPostBack check.
My code is working well.
Here is it.
public partial class _Default : System.Web.UI.Page {
protected void Page_Load (object sender, EventArgs e) { }
protected override void OnInit (EventArgs e) {
base.OnInit(e);
//if (!IsPostBack) {
string listClientID = BulletedList1.ClientID.Replace('_', '$');
int counter = 0;
List<SomeClass> items = new List<SomeClass>(){ new SomeClass() { Rank = 1, Title = "2"},
new SomeClass () {Rank = 2, Title = "Two"}};
foreach (var item in items) {
// Add Button
ListItem listItem = new ListItem();
listItem.Value = "buttonItem" + item.Rank;
listItem.Text = " " + item.Title;
listItem.Attributes.Add("onclick", "__doPostBack('" + listClientID + "', '" + counter.ToString() + "')");
BulletedList1.Items.Add(listItem);
counter++;
}
//}
}
protected void MenuItem_Click (object sender, BulletedListEventArgs e) {
Response.Write(e.Index);
}
class SomeClass {
public int Rank;
public string Title;
}
}

Probably UpdatePanel is causing the trouble. I would try pulling it out of UpdatePanel and then would see(which I believe it should) if that works?
Secondly, you can probably just populate the list items Values and Texts only, and then under mnuMainMenu_MenuItemClick(object sender, MenuEventArgs e) event; look for the specific item that has been clicked (e.Item.* public properties), and then probably would use Response.Redirect() to do the job; well, just thinking out loud...

Related

Link linkbutton in method on page to linkbutton in master page

I'm attempting to make a cart system for my C# based website using ASP.NET.
Currently I've created a method which updates a linkbutton which I have in the master page.
When I try and reference the linkbutton in a product page it errors saying 'productpages_stand' does not contain a definition for 'lbnCart' and no extension method 'lbnCart' accepting a first argument of type 'productpages_stand' could be found'.
Am I not able to link a linkbutton to a masterpage from a web form?
The method:
private void updateCartSummary()
{
// get number of items in cart and show summary in link button
ArrayList cart = (ArrayList)Session["CART"];
int totalItems = cart.Count;
this.lbnCart.Text = "Cart : " + "(" + totalItems + ")";
}
Link button from masterpage:
<asp:LinkButton ID="lbnCart" CssClass="shoppingcarttext button small third" runat="server">Cart : (0)</asp:LinkButton>
EDIT:
Main code segment which is erroring on the product page:
public partial class productpages_atomosninja : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) // first time
{
updateCartSummary();
}
LinkButton lbnCart = (LinkButton)Master.FindControl("lbnCart");
if (lbnCart != null)
{
lbnCart.Text = "Cart : " + "(" + totalItems + ")";
}
}
protected void btnAtomos_Click(object sender, EventArgs e)
{
Trace.Warn("Adding an item to the cart");
// create cart item object with the book details
CartItem cartItem = new CartItem();
cartItem.setCost(299.00);
cartItem.setItemName("Atomos Ninja 2");
// extract arraylist from session variable
ArrayList arrCart = (ArrayList)Session["CART"];
// add the cartitem object to the arraylist
arrCart.Add(cartItem);
//store arrayList back into the session variable
Session.Add("CART", arrCart);
updateCartSummary();
}
private void updateCartSummary()
{
// get number of items in cart and show summary in link button
ArrayList cart = (ArrayList)Session["CART"];
int totalItems = cart.Count;
this.lbnCart.Text = "Cart : " + "(" + totalItems + ")";
}
}
Error for totalItems in the page_load method saying it doesn't exist since it isn't defined until later in the document.
EDIT 2:
After adding the code where #David said it still errors.
public partial class product : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) // first time
{
updateCartSummary();
}
}
LinkButton lbnCart = (LinkButton)Master.FindControl("lbnCart");
if (lbnCart != null)
{
lbnCart.Text = "Cart : " + "(" + totalItems + ")";
}
}
While there is a relationship between the Master Page and the Content Page, this doesn't change how classes and properties and general scope work in the C# language. The Master Page and the Content Page are different classes, so you can't directly reference each other's class members like that.
However, the class for the Content Page does have a property on it called Master which references the Master Page. And that property can be used to access members of the Master Page object.
For example:
private void updateCartSummary()
{
// this part is unchanged from what you have
ArrayList cart = (ArrayList)Session["CART"];
int totalItems = cart.Count;
// here, find the control from the "Master" property
LinkButton lbnCart = (LinkButton) Master.FindControl("lbnCart");
if(lbnCart != null)
{
lbnCart.Text = "Cart : " + "(" + totalItems + ")";
}
}

Calling method from an <li> element , inside the Literal.text string

I am having the following problem: I want to call a method whenever a specific li is clicked. Problem is that the li is dynamically created in a literal.text string, where I do import things from my database.
Whenever I try to call a method it does not work. I want to call a method whenever the user clicks on each li and get that li information inside my method (haven't wrote the method code yet, because I can't get it called.)
Thoughts?
protected void Page_Load(object sender, EventArgs e)
{
string conString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source="
+ Server.MapPath("~/ebookstoredb.mdb");
using (OleDbConnection con = new OleDbConnection(conString))
{
con.Open();
string query = "SELECT * FROM CATEGORY";
using (OleDbCommand cmd = new OleDbCommand(query, con))
{
OleDbDataReader reader = cmd.ExecuteReader();
String msg = "";
while (reader.Read())
{
lit1.Text += "<ul>" + "<li runat=\"server\" OnClick=\"ProductsInfo\">" + reader["ID"]
+ "," + reader["Name"]
+ "</li>"
+ "</ul>";
}
reader.Close();
}
con.Close();
}
}
protected void ProductsInfo(object sender, EventArgs e)
{
Response.Redirect("Default.aspx");
}
Unfortunately, you cannot create server-side events on a Literal Control.
However, you can add client-side javascript functionality to post back a request.
In your aspx using:
<div>
<asp:Literal runat="server" ID="lit1"></asp:Literal>
</div>
Your aspx.cs should contain:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
lit1.Text += "<ul>" + "<li \' onclick=\'javascript: __doPostBack(\"getProduct\", \"1\");\'>"
+ "Product " + "1"
+ "</li>"
+ "</ul>";
}
if (Request.Form["__EVENTTARGET"] != null && Request.Form["__EVENTTARGET"] == "getProduct")
{
getProduct_Click(null, null);
}
}
private void getProduct_Click(object sender, System.EventArgs e)
{
Response.Write("You Clicked on " + Request.Form["__EVENTARGUMENT"]);
}
This will set up each li to pass their own value to the event argument hidden control and perform a postback to the server.
You can then check if the event target is the required one and call a method with the value that was posted back.
Just change the sample lit1 text above to iterate through your data.
I've never used literals before, but from reading about them... with a literal displaying just static html, you will need to have each li call a javascript function that will then do a postback to the method you want. So build your li like this:
lit1.Text += "<ul><li><a onclick=\"CallProductInfo(" + reader["ID"]+ ")\">" + reader["ID"]
+ "," + reader["Name"]
+ "</a></li></ul>";
Then you have to have a javascript function that does the actual postback to your server side code or redirects to the products info page with the passed id. That is, in your page (not the code behind), have a script something like this for the postback...
<script>
function CallProductInfo(id)
{
__doPostBack('ProductInfoId', id);
}
</script>
In you code behind, in your page load event handler, you'd have something like this:
if (Request["__EVENTTARGET"] == "ProductInfoId")
{
ProductInfo(Convert.ToInt64(Request["__EVENTARGUMENT"]));
}
Ok so guys i found out what was the problem. Our mr.genious instructor told us today that we can use a datagrid..Sigh.
Thanks everyone for your replies!

Dynamic controls disappear ASP.NET C# (Loading controls depending on a DropDownList selection)

I'm new in ASP.NET; I have a DropDownList in a page (with a masterpage):
<asp:DropDownList ID="cmbPrueba" runat="server" OnSelectedIndexChanged="cmbPrueba_SelectedIndexChanged" AutoPostBack="true">
<asp:ListItem Value="0">Compresor de Aire</asp:ListItem>
<asp:ListItem Value="1">Compresor/Unidad de Refrigeración</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="btnActualizar" runat="server" Text="Actualizar" OnClick="btnActualizar_Click" />
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
Depending of the DropDownList (cmbPrueba) the placeHolder creates controls using the string array; (I made the string arrays simulating string result of database).
So, if I take itemIndex=0 ("CompresorDeAire) I will create: "TextBox", "Calendar", "TextBox";
if I take index=1 (CompresorUnidadDeRefrigeracion ) the controls are: "DropDownList", "TextBox", "Calendar", "Calendar", "TextBox"... but there is a "DropDownList" control, so I will full it with this info:
private string[] CompresorUnidadDeRefrigeracionTipoCompresor = new string[] { "Compresor Alternativo", "Compresor de Tornillo", "Unidad de Refrigeración" };
And so on. Here is the code:
public partial class Controles : System.Web.UI.Page
{
private Label _Label;
private TextBox _TextBox = new TextBox();
private Calendar _Calendar = new Calendar();
private DropDownList _DropDownList = new DropDownList();
private string[] CompresorDeAire = new string[] { "TextBox", "Calendar", "TextBox" };
private string[] CompresorUnidadDeRefrigeracion = new string[] { "DropDownList", "TextBox", "Calendar", "Calendar", "TextBox" };
private string[] CompresorUnidadDeRefrigeracionTipoCompresor = new string[] { "Compresor Alternativo", "Compresor de Tornillo", "Unidad de Refrigeración" };
private string[] BombaElectrica = new string[] { "TextBox", "TextBox", "TextBox", "TextBox", "TextBox", "TextBox" };
protected void Page_Load(object sender, EventArgs e)
{
LoadInfo(CompresorDeAire);
}
private void LoadInfo(string[] Arreglo)
{
for (int i = 0; i < Arreglo.Length; i++)
{
_Label = new Label();
_TextBox = new TextBox();
_Calendar = new Calendar();
_DropDownList = new DropDownList();
_Label.Text = Arreglo[i].ToString() + i.ToString();
_Label.ID = _Label.Text;
PlaceHolder1.Controls.Add(_Label);
PlaceHolder1.Controls.Add(new LiteralControl("<br />"));
if (Arreglo[i] == _TextBox.GetType().Name.ToString())
{
_TextBox.ID = "txt" + _Label.ID;
//_TextBox.AutoPostBack = true;
PlaceHolder1.Controls.Add(_TextBox);
}
else if (Arreglo[i] == _Calendar.GetType().Name.ToString())
{
_Calendar.ID = "cln" + _Label.ID;
PlaceHolder1.Controls.Add(_Calendar);
}
else if (Arreglo[i] == _DropDownList.GetType().Name.ToString())
{
_DropDownList.ID = "cmb" + _Label.ID;
//_DropDownList.AutoPostBack = true;
foreach (var item in CompresorUnidadDeRefrigeracionTipoCompresor)
{
int j = 0;
_DropDownList.Items.Add(item);
j++;
}
PlaceHolder1.Controls.Add(_DropDownList);
}
PlaceHolder1.Controls.Add(new LiteralControl("<br /><br />"));
}
}
protected void cmbPrueba_SelectedIndexChanged(object sender, EventArgs e)
{
txtMensaje.Text = "";
PlaceHolder1.Controls.Clear();
switch (cmbPrueba.SelectedIndex)
{
case 0:
this.LoadInfo(CompresorDeAire);
break;
case 1:
this.LoadInfo(CompresorUnidadDeRefrigeracion);
break;
case 2:
this.LoadInfo(BombaElectrica);
break;
}
}
protected void btnActualizar_Click(object sender, EventArgs e)
{
txtMensaje.Text = "";
for (int i = 0; i < PlaceHolder1.Controls.Count; i++)
{
switch (PlaceHolder1.Controls[i].GetType().Name.ToString())
{
case "TextBox":
TextBox TB = PlaceHolder1.FindControl(PlaceHolder1.Controls[i].ID) as TextBox;
txtMensaje.Text += PlaceHolder1.Controls[i].GetType().Name + " " + PlaceHolder1.Controls[i].ID + " " + TB.Text + "\n";
TB.Text += "*";
break;
case "Calendar":
Calendar Cal = PlaceHolder1.FindControl(PlaceHolder1.Controls[i].ID) as Calendar;
txtMensaje.Text += PlaceHolder1.Controls[i].GetType().Name + " " + PlaceHolder1.Controls[i].ID + " " + Cal.SelectedDate.ToShortDateString() + "\n";
break;
case "DropDownList":
DropDownList DD = PlaceHolder1.FindControl(PlaceHolder1.Controls[i].ID) as DropDownList;
txtMensaje.Text += PlaceHolder1.Controls[i].GetType().Name + " " + PlaceHolder1.Controls[i].ID + " " + DD.Text + "\n";
break;
}
}
}
protected void btnLimpiar_Click(object sender, EventArgs e)
{
PlaceHolder1.Controls.Clear();
txtMensaje.Text = "";
}
}
When I run the code by default is Index = 0 , I use the textbox and calendar, and click "Actualizar" and I can see the info in the text box, when I choose Index=1 (and load the 2nd array) all the new controls show up, but if I choose a date or I write in the textbox and click in the buttom "Actualizar" the page return to the previous page (array 1).
I appreciate your help! thanks.
I am assuming that when you say “the page return to the previous page (array 1).” That you mean the first array (in the zero-th element)
The problem is that .NET will not automatically re-create the dynamic controls for you on the post back. You have to handle that.
Here are the basic steps for the first page request:
Execute the Page_load event, which calls LoadInfo for CompresorDeAir.
Then when you selected a different entry in the dropdown and then click Actualizer button then it does a post back with these basic steps:
Execute the Page_load event, which calls LoadInfo for CompresorDeAir.
Execute cmbPrueba_SelectedIndexChanged which throws away the dynamic controls that were added in the page load and loads the control for the selected index.
Execute btnActualizer_Click event which shows the controls in the dynamic place holder, these being the ones for the selected dropdown value.
Then when you change the text or date and then click Actualizer button it does these steps:
Execute the Page_load event, which calls LoadInfo for CompresorDeAir.
Execute btnActualizer_Click event which shows the controls in the dynamic place holder. In this case the ones from the page load are shown. the controls from the prior selected dropdown list item do not get created.
The only time the controls from the selected item in the dropdown list are added to the place holder is when the selected item changes for the dropdown.
The solution is put a hidden variable in the form to hold the last selected item from the drop down. Everytime the selected index changes then update this hidden value. In the page load event, on a postback, load the appropriate array based on that hidden value.

How to dynamically assign "is-active" class based on current focus in C#

I have a class called "is-active" and it has a colored arrow that sticks out from the nav into the main content based on which link is the current active one. The code runs a foreach and pulls all the categories from the database. How do I get the "is-active" class to display only for the current link? I know it works since I put it in the openList control and it displayed on all five categories, I just don't know how to get it to display on only the selected category.
Thank you in advance for your help!
Below is my code for the categories and link button:
protected override void CreateChildControls()
{
LiteralControl openingDiv = new LiteralControl("<div id='MainPanel'>");
LiteralControl closingDiv = new LiteralControl("</div>");
this.Controls.Add(openingDiv);
foreach (DataRow dr in ds.Tables[0].Rows)
{
LiteralControl openList = new LiteralControl("<li class='" + dr["CategoryColor"].ToString() + "'>");
LiteralControl closeList = new LiteralControl("</li>");
Label lblNumber = new Label();
LinkButton myLinkButton = new LinkButton();
myLinkButton.Text = "<span class='number'>" + dr["CategoryNumber"] + "</span>"+ dr["CategoryName"].ToString();
myLinkButton.CommandArgument = dr["Category_ID"].ToString();
myLinkButton.Click += myLinkButton_Click;
this.Controls.Add(openList);
this.Controls.Add(myLinkButton);
this.Controls.Add(closeList);
}
this.Controls.Add(closingDiv);
}
void myLinkButton_Click(object sender, EventArgs e)
{
LinkButton btn = (LinkButton)(sender);
Session["CategoryID"] = btn.CommandArgument;
Response.Redirect(Request.RawUrl);
}

SelectionList always returns NULL

I have a very strange issue where SelectionList always returns NULL when i try check its Selected Item/Value. I Googled a bit and I found out that when i click the submit button, the page is being refreshed and the SelectionList is being data bound again so it will revert back to its original behavior.
Then i tried enclosing the binding code in the Page_Load event in a !IsPostBack but still when i try to access the Selected property it is null and an exception is thrown.
Any help would be greatly appreciated.
My code goes something like this... (the braces are not matched properly)
static SelectionList[] Symptoms;
static string UserID = "";
cmbSymptoms1,cmbSymptoms2,cmbSymptoms3 and cmbSymptoms4 are SelectionLists. I took them in to an array of SelectionList and then set the properties.
I had to make them static or else when i click the button to update, they will not retain their values. Any idea why they don't retain the values?
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack == false)
{
//System.Diagnostics.Debug.WriteLine("Not IsPostBack");
if (Request.QueryString["id"] != null && Request.QueryString.ToString() != "")
{
//System.Diagnostics.Debug.WriteLine("id query string is not null :- " + Request.QueryString["id"]);
myclass = new Class1();
UserID = Request.QueryString["id"];
Symptoms = new SelectionList[4];
Symptoms[0] = cmbSymptoms1;
Symptoms[1] = cmbSymptoms2;
Symptoms[2] = cmbSymptoms3;
Symptoms[3] = cmbSymptoms4;
System.Data.DataTable dt = myclass.getAllSymptoms();
foreach (SelectionList listItem in Symptoms)
{
listItem.DataSource = dt;
listItem.DataTextField = "symptomsname";
listItem.DataValueField = "symptomsid";
listItem.DataBind();
listItem.Items.Insert(0, new MobileListItem("None"));
}
And in the update button click event
protected void cmbUpdate_Click(object sender, EventArgs e)
{
foreach (SelectionList listItem in Symptoms)
{
if (listItem.SelectedIndex != 0)
{
cmd.CommandText = "INSERT INTO Patient_Symptom (patientid,symptomid) VALUES (" + UserID + ",'" + listItem.Selection.Value + "')";
cmd.ExecuteNonQuery();
}
}
}
You can try two things. Try placing the databinding code in the PreRender event. The second and better option would be to use an ObjectDataSource controls and bind the control declaratively.

Categories

Resources