Dynamic LinkButton on GridView PagerTemplate not firing event - c#

I am doing a custom Pager Template for a gridview & trying to get something like:
< 1 2 3 4 >
I am having problems clicking on the numbers...
Inside the PagerTemplate i have a Placeholder named "phLinks" that is being filled on the DataBound Event like this:
protected void DataBound(object sender, EventArgs e)
{
if (grid.PageCount > 1)
{
for (int i = 0; i < grid.PageCount; i++)
{
phLinks.Controls.Add(new LiteralControl("<li>"));
LinkButton lb = new LinkButton { Text = (i + 1).ToString(), Enabled = grid.PageIndex != i, CommandArgument = i.ToString() };
lb.Command += new CommandEventHandler(lb_Command);
lb.CommandName = "Button";
//lb.Click += new EventHandler(lb_Click);
phLinks.Controls.Add(lb);
phLinks.Controls.Add(new LiteralControl("</li>"));
}
}
}
Please note that I have tried first the Click Event and then the Command Event, in both cases i get a post back but the event is not triggered...
What am i missing here?

Either bind your GridView on every postback :
protected void Page_Load(object sender, EventArgs e)
{
MyGridView.DataBind();
}
OR turn off ViewState for your GridView::
<asp:GridView ID="MyGridView" EnableViewState="false" ... />.

Related

CheckedChanged event is not fired

In my WebForm I want the total price changed when the user check one product but I have this problem with my code ,
the CheckedChanged event is not firing when I check the CheckBox
It is firing only when I click the Button(used for as clear button) , and I didn't include that code within the button event !
Here is my code:
public partial class _Default : System.Web.UI.Page
{
int total = 0;
String strtotal;
protected void ckb1_CheckedChanged(object sender, EventArgs e)
{
if (ckb1.Checked)
{
total = total + 100;
strtotal = total.ToString();
lbl2.Text = strtotal;
}
}
protected void ckb2_CheckedChanged(object sender, EventArgs e)
{
if (ckb2.Checked)
{
total = total + 80;
strtotal = total.ToString();
lbl2.Text = strtotal;
}
}
protected void ckb3_CheckedChanged(object sender, EventArgs e)
{
if (ckb3.Checked)
{
total = total + 70;
strtotal = total.ToString();
lbl2.Text = strtotal;
}
}
protected void Button3_Click(object sender, EventArgs e)
{
TextBox1.Text = " ";
ckb1.Checked = false;
ckb2.Checked = false;
ckb3.Checked = false;
}
}
All ASP.NET Server controls except Button, Hyperlink and LinkButton have a default AutoPostBack property of false, So you should set AutoPostBack="true" in your CheckBox:
<asp:CheckBox ID="ckb1" runat="server" AutoPostBack="true" OnCheckedChanged="ckb1_CheckedChanged" />
It is firing only when I click the button
As I said this is because the Button have AutoPostBack property of true by default so after you checked the CheckBox and then click the button the CheckBox state automatically posts back to the server.

Button Click in a TableCell never fires and table disappears

I my ASP.NET Webforms app, I have a table in which I add all data dynamically. One row contains Buttons in each cell. I want the button to fire onclick event when the user clicks on it. But, with the below code, the event never fires and the table disappears. Here's the code :
<asp:Table ID="floorTable" runat="server" Width="100%" GridLines="Both">
</asp:Table>
In Code behind
// This method is called on a DropDownList SelectedItemChanged Event - so
// the buttons cannot be created in Page_Load or so. Have to create
// totally based on the DropDown selected item.
private void PopulateFloorRow(int floorNo, FloorPattern fp)
{
int cols = fp.UnitPattern.Count;
// HEADER ROW
TableRow thead = new TableRow();
thead.Width = Unit.Percentage(100);
thead.TableSection = TableRowSection.TableHeader;
TableCell theadCell = new TableCell();
theadCell.ColumnSpan = cols;
Label title = new Label();
title.Text = "Floor # " + floorNo;
theadCell.Controls.Add(title);
thead.Controls.Add(theadCell);
TableRow planRow = GetFloorPlan(floorNo, fp);
TableRow tr = new TableRow();
TableCell tc = null;
int tcWidPerc = (int)fp.UnitPattern.Count / 100;
foreach (UnitPattern up in fp.UnitPattern)
{
tc = new TableCell();
Button imgBtn = new Button();
// On Adding BELOW Line - ERROR - 0x800a1391 - JavaScript runtime error: 'UnitLinkClicked' is undefined
//imgBtn.Attributes.Add("onClick", "UnitLinkClicked(this)");
imgBtn.CommandArgument = up.UnitPatternId.ToString(); // I want to know which button is pressed. So, sort of Tag
imgBtn.Click += new EventHandler(UnitLinkClicked);
imgBtn.BorderWidth = Unit.Pixel(10);
imgBtn.BorderColor = Color.Transparent;
imgBtn.Width = Unit.Percentage(100);
if (up.UnitNo != null)
{
imgBtn.Text = up.UnitNo;
}
tc.Controls.Add(imgBtn);
tr.Controls.Add(tc);
}
floorTable.Rows.Add(thead);
floorTable.Rows.Add(planRow);
floorTable.Rows.Add(tr);
// Create Footer
PopulateTableFooter(cols);
}
protected void UnitLinkClicked(object sender, EventArgs e)
{
Button btn = (Button)(sender);
string upId = btn.CommandArgument;
System.Diagnostics.Debug.WriteLine("LINK Button clicked Of UP ID :" + upId);
}
EDIT : CODE OF SELECTEDiNDEXCHANGED ADDED
My DropDown_SelectedIndexChanged Code :
protected void floorDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
if (selectedProject == null)
selectedProject = _db.Projects.Find(projectsList.SelectedValue);
System.Diagnostics.Debug.WriteLine("SELCTED Project = " + selectedProject.ProjectId);
// "Select Floor" is selected, so Hide floor Table
if (floorDropDownList.SelectedValue == "-1")
{
floorTable.Visible = false;
}
else
{
int floorNo = int.Parse(floorDropDownList.SelectedValue);
if (floorNo > 0)
{
PopulateFloorRow(floorNo, (FloorPattern)selectedProject.FloorPattern.ElementAt(floorNo - 1));
}
}
}
If I had selected "3" in my drop down, the table appears as expected. I click on a button and the table disappears, but the value in the drop down in still "3" only.
EDIT PART OVER
With the above code, I when I click on a button, the UnitLinkClicked event is never fired (I had added breakpoint) and the whole table disappears.
Can you say what problem can this be ? A button by default is meant to be AutoPostBack & it doesn't have that property too. What am I missing here and how to solve this. Am stuck on this since days and trying to figure out.
Any help is highly appreciated.
Thanks
You need to set an ID for your button. Without the ID the event will not be fired.
Button imgBtn = new Button();
imgBtn.ID = "imgBtn";
Also make sure that each button you add has a unique ID. You could probably concatenate the floor no. or any other fields to arrive at a unique name.
Also, the table will disappear unless, you manage that in your Page_Load. You need to reload the table if the DropDown has a selected index.
EDIT: Code Sample
.cs code
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
PopulateFloorRow();
}
}
protected void cmb_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateFloorRow();
}
private void PopulateFloorRow()
{
floorTable.Rows.Clear();
for (int i = 0; i < 2; i++)
{
TableRow tableRow = new TableRow();
tableRow.Cells.Add(new TableCell());
tableRow.Cells.Add(new TableCell());
tableRow.Cells[0].Controls.Add(new Label() { Text = cmb.SelectedItem.Text });
Button button = new Button();
button.ID = "btn" + i.ToString();
button.Text = "Click";
button.Click += button_Click;
tableRow.Cells[1].Controls.Add(button);
floorTable.Rows.Add(tableRow);
}
}
void button_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
.aspx code
<asp:DropDownList id="cmb" runat="server" OnSelectedIndexChanged="cmb_SelectedIndexChanged" AutoPostBack="true"><asp:ListItem>One</asp:ListItem><asp:ListItem>Two</asp:ListItem></asp:DropDownList>
<asp:Table ID="floorTable" runat="server" Width="100%" GridLines="Both">
</asp:Table>

How to find a control (textbox) that was created during rowCommand and get its value

I have added a GridView to my webform. I then bounded data to the gridview programatically, followed by adding a RowDataBound function so that I can have each cell, in the gridView selectable as such:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton _singleClickButton = (LinkButton)e.Row.Cells[0].Controls[0];
string clickInfo = ClientScript.GetPostBackClientHyperlink(_singleClickButton, "");
// Add events to each editable cell
for (int columnIndex = 3; columnIndex < e.Row.Cells.Count; columnIndex++)
{
// Add the column index as the event argument parameter
string jsClick = clickInfo.Insert(clickInfo.Length - 2, columnIndex.ToString());
// Add this javascript to the onclick Attribute of the cell
e.Row.Cells[columnIndex].Attributes["onclick"] = jsClick;
// Add a cursor style to the cells
e.Row.Cells[columnIndex].Attributes["style"] += "cursor:pointer;cursor:hand;";
}
}
}
...So then what i wanted to do is that whenever a cell is selected, turn that cell red and add a textbox so i can enter a value.. Shown below
<Columns>
<asp:ButtonField CommandName="CellClick" Visible="false" ControlStyle- CssClass="redCell"></asp:ButtonField>
</Columns>
codebehind:
public void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.ToString() == "CellClick")
{
//INDEX INFO
int selectedRowIndex = Convert.ToInt32(e.CommandArgument.ToString());
int selectedColumnIndex = Convert.ToInt32(Request.Form["__EVENTARGUMENT"].ToString());
//TRIGGERS EVENT FOR SELECTED CELL
GridView1.Rows[selectedRowIndex].Cells[selectedColumnIndex].Attributes["style"] += "background-color:Red;";
TextBox scheduleBox = new TextBox();
scheduleBox.CssClass = "redCell";
scheduleBox.ID = "ActiveCell";
scheduleBox.Width = 35;
this.GridView1.Rows[selectedRowIndex].Cells[selectedColumnIndex].Controls.Add(scheduleBox);
scheduleBox.Focus();
//LABEL INDEX INFO
lblCell.Text = (selectedColumnIndex - 2).ToString();
//LABEL HEADER & ROW TITLES
lblStartTime.Text = GridView1.Rows[selectedRowIndex].Cells[1].Text;
}
} GridView1.DataBind();
}
what I want to do now is once I press enter, get the value that currently resides in the texbox that was created programmatically and for now just display that value on a messagebox or whateevr (what Im really going to do is update a database but first I just need to find out how to get that value)
<asp:Panel runat="server" DefaultButton="Button1">
<asp:Button ID="Button1" CssClass="ActiveCell" runat="server" Style="display: none" OnClick="Button1_Click1" /></asp:Panel>
and the function Im using is this:
protected void Button1_Click1(object sender, EventArgs e)
{
var schedule = FindControl("ActiveCell") as TextBox;
ScriptManager.RegisterStartupScript(this, typeof(Page),
"alert", "alert('VALUE GOES HERE FROM TEXTBOX');", true);
}
So now my question: How can i get the value from ScheduleBox?
If I understand your question correctly, you should be able to use:
<%=schedule.ClientID %>.value
I am admittedly not a javascript expert, so let me know if that helps.
also, is the
var schedule = FindControl("ActiveCell") as TextBox;
returning the textbox correctly?
EDIT: if that doesn't work, try
<%=ActiveCell.ClientID %>.value
Have you tried looking into the controls of the cell of the selected row?
To work around the lack of a selectedColumnIndex in the GridView, I had to change your "GridView1_RowCommand" event to replace one line (to set the ID) and add one more:
scheduleBox.ID = "ActiveCell_" + selectedRowIndex.ToString() + "_" + selectedColumnIndex.ToString();
scheduleBox.TextChanged += scheduleBox_TextChanged;
It would look something like this:
int selectedColumnIndex = 0;
int selectedRowIndex = 0;
string lastUserInputText = string.Empty;
public void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.ToString() == "CellClick")
{
//INDEX INFO
selectedRowIndex = Convert.ToInt32(e.CommandArgument.ToString());
selectedColumnIndex = Convert.ToInt32(Request.Form["__EVENTARGUMENT"].ToString());
//TRIGGERS EVENT FOR SELECTED CELL
GridView1.Rows[selectedRowIndex].Cells[selectedColumnIndex].Attributes["style"] += "background-color:Red;";
TextBox scheduleBox = new TextBox();
scheduleBox.CssClass = "redCell";
//This formats the ID so its unique, and now the TextBox contains the row and colummn indexes:
scheduleBox.ID = "ActiveCell_" + selectedRowIndex.ToString() + "_" + selectedColumnIndex.ToString();
scheduleBox.TextChanged += scheduleBox_TextChanged;
scheduleBox.Width = 35;
this.GridView1.Rows[selectedRowIndex].Cells[selectedColumnIndex].Controls.Add(scheduleBox);
scheduleBox.Focus();
//LABEL INDEX INFO
lblCell.Text = (selectedColumnIndex - 2).ToString();
////LABEL HEADER & ROW TITLES
lblStartTime.Text = GridView1.Rows[selectedRowIndex].Cells[1].Text;
}
GridView1.DataBind();
}
//The following event gets the current index of the Row and the column where the user is changing the text
void scheduleBox_TextChanged(object sender, EventArgs e)
{
TextBox txtSelected = (TextBox)sender;
string[] selectedValues = txtSelected.ID.Split(new char[] { '_' });
selectedRowIndex = int.Parse(selectedValues[1]);
selectedColumnIndex = int.Parse(selectedValues[2]);
//you could also use it to get the text directly while the user is editing it:
lastUserInputText = txtSelected.Text;
}
//This gets the text for the selected row and column. But if you only have 1 column with a TextBox it would be easier to just use the column index constant instead of doing it dynamically. However, remember you already have this value in the "lastUserInputText" variable. If you use that the following code may not be necessary:
string GetTextFromSelectedRowTextBox()
{
string textBoxValue = string.Empty;
foreach (Control curControl in this.GridView1.Rows[selectedRowIndex].Cells[selectedColumnIndex].Controls)
{
if (curControl is TextBox)
{
TextBox txtScheduleBox = (TextBox)curControl;
textBoxValue = txtScheduleBox.Text;
break;
}
}
return textBoxValue;
}

Textbox disappears when linkbutton is clicked

I have a problem. I'm trying to make some panels, and in these panels I would like to have some linkbuttons, when the user click a linkbutton of a panel a textbox will appear in that panel, when I click in another linkbutton the textboxes of that panel also appear without problem but when I click in the other linkbutton the texboxes created in the previous panel disappears.
Here is my code:
public partial class _Default : Page
{
Label myLabel1;
Label myLabel2;
protected void Page_Load(object sender, EventArgs e)
{
myLabel1 = new Label();
myLabel2 = new Label();
Panel1.Controls.Add(myLabel1);
Panel2.Controls.Add(myLabel2);
if (!Page.IsPostBack)
{
//Remove the session when first time page loads.
Session.Remove("clicks");
Session.Remove("clicks2");
}
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
int rowCount = 0;
//initialize a session.
rowCount = Convert.ToInt32(Session["clicks"]);
rowCount++;
//In each button clic save the numbers into the session.
Session["clicks"] = rowCount;
//Create the textboxes and labels each time the button is clicked.
for (int i = 0; i < rowCount; i++)
{
TextBox TxtBoxU = new TextBox();
TxtBoxU.ID = "TextBoxU" + i.ToString();
//Add the labels and textboxes to the Panel.
Panel1.Controls.Add(TxtBoxU);
}
myLabel1.Text = rowCount + "";
}
protected void LinkButton2_Click(object sender, EventArgs e)
{
int rowCount2 = 0;
//initialize a session.
rowCount2 = Convert.ToInt32(Session["clicks2"]);
rowCount2++;
//In each button clic save the numbers into the session.
Session["clicks2"] = rowCount2;
//Create the textboxes and labels each time the button is clicked.
for (int i = 0; i < rowCount2; i++)
{
TextBox TxtBoxU = new TextBox();
TxtBoxU.ID = "TextBoxU" + i.ToString();
//Add the labels and textboxes to the Panel.
Panel2.Controls.Add(TxtBoxU);
}
myLabel2.Text = rowCount2 + "";
}
}
And here is the other part:
<form id="form1" runat="server">
<p>
Part I</p>
<asp:Panel ID="Panel1" runat="server" Height="53px">
<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">Add to 1</asp:LinkButton>
<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</asp:Panel>
<asp:Panel ID="Panel2" runat="server" Height="51px">
<asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton2_Click">Add to 2</asp:LinkButton>
<br />
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
</asp:Panel>
</form>
Since the text boxes are dynamically created, when the page loads everything needs to be re-built, but the code you posted only re-builds the text boxes for one of the panels when the particular link button for that panel is being clicked. However, your code is just building the one panel again, because that is all that your click event handlers for the link buttons are telling it to do.
I suggest combining the logic into a single method that does the building and then each link button click event handler can update its own count and pass it to the method, like this:
private void BuildTextBoxes(int rowCount1, int rowCount2)
{
for (int i = 0; i < rowCount; i++)
{
TextBox TxtBoxU = new TextBox();
TxtBoxU.ID = "TextBoxU" + i.ToString();
//Add the labels and textboxes to the Panel.
Panel1.Controls.Add(TxtBoxU);
}
myLabel1.Text = rowCount + "";
for (int i = 0; i < rowCount2; i++)
{
TextBox TxtBoxU = new TextBox();
TxtBoxU.ID = "TextBoxU" + i.ToString();
//Add the labels and textboxes to the Panel.
Panel2.Controls.Add(TxtBoxU);
}
myLabel2.Text = rowCount2 + "";
}
Now in your link button click event handlers, you will need to update the one count, but pass both to the method, like this:
protected void LinkButton1_Click(object sender, EventArgs e)
{
int rowCount = 0;
//initialize a session.
rowCount = Convert.ToInt32(Session["clicks"]);
rowCount++;
//In each button clic save the numbers into the session.
Session["clicks"] = rowCount;
BuildTextBoxes(rowCount, Convert.ToInt32(Session["clicks2"]));
}
protected void LinkButton2_Click(object sender, EventArgs e)
{
int rowCount2 = 0;
//initialize a session.
rowCount2 = Convert.ToInt32(Session["clicks2"]);
rowCount2++;
//In each button clic save the numbers into the session.
Session["clicks2"] = rowCount2;
BuildTextBoxes(Convert.ToInt32(Session["clicks1"]), rowCount2));
}
Now, whether you click the first or second link button, all of the text boxes will be recreated; with only the particular link button incrementing the number of rows.
When there is a post-back to the server following the click on the link an entirely new HTML page is generated and returned to the client. In the click event handler in your code you are adding additional controls to the ones in your aspx markup. These are then included in the HTML returned to the client. But the server is state-less and will not remember that you added these the next time there is a request from the client. You will need to add them again every time there is a post-back.
Maybe try to move your logic to add the text boxes into a separate method and then call it with the appropriate values in your click.
Something like this:
protected void LinkButton1_Click(object sender, EventArgs e)
{
int rowCount = Convert.ToInt32(Session["clicks"]) + 1;
Session["clicks"] = rowCount;
int rowCount2 = Convert.ToInt32(Session["clicks2"]) + 1;
Session["clicks2"] = rowCount2;
AddTextBoxes(rowCount, Panel1, myLabel1);
AddTextBoxes(rowCount2, Panel2, myLabel2);
}
protected void LinkButton2_Click(object sender, EventArgs e)
{
int rowCount = Convert.ToInt32(Session["clicks"]) + 1;
Session["clicks"] = rowCount;
int rowCount2 = Convert.ToInt32(Session["clicks2"]) + 1;
Session["clicks2"] = rowCount2;
AddTextBoxes(rowCount, Panel1, myLabel1);
AddTextBoxes(rowCount2, Panel2, myLabel2);
}
protected void AddTextBoxes(int numberToAdd, Panel panel, Label label)
{
//In each button clic save the numbers into the session.
numberToAdd = rowCount;
//Create the textboxes and labels each time the button is clicked.
for (int i = 0; i < rowCount; i++)
{
TextBox TxtBoxU = new TextBox();
TxtBoxU.ID = "TextBoxU" + i.ToString();
//Add the labels and textboxes to the Panel.
panel.Controls.Add(TxtBoxU);
}
label.Text = rowCount + "";
}

Dynamically create textbox on button click

I have created a button whereby when it is clicked, it should display 3 textboxes in a row. However, every time i click the submit button, the textbox would display 2 rows(which is 6 textboxes). And subsequently increase 2 rows at every click.
Is there anyway that it could just increase one row of textbox at every click??
Here is the code infront:
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
</div>
</form>
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
// Add any controls that have been previously added dynamically
for (int i = 0; i < TotalNumberAdded; i++)
{
AddControls(i + 1);
}
// Attach the event handler to the button
Button1.Click += new EventHandler(Button1_Click);
}
protected void Button1_Click(object sender, EventArgs e)
{
// Increase the number added and add the new label and textbox
TotalNumberAdded++;
AddControls(TotalNumberAdded);
}
private void AddControls(int controlNumber)
{
TextBox TxtBoxU = new TextBox();
TextBox TxtBoxE = new TextBox();
TextBox TxtBoxY = new TextBox();
Label lblU = new Label();
Label lblE = new Label();
Label lblY = new Label();
TxtBoxU.ID = "TextBoxU" + controlNumber;
TxtBoxE.ID = "TextBoxE" + controlNumber;
TxtBoxY.ID = "TextBoxY" + controlNumber;
lblU.ID = "LabelU" + controlNumber;
lblE.ID = "LabelE" + controlNumber;
lblY.ID = "LabelY" + +controlNumber;
lblU.Text = "User : ";
lblE.Text = "E-Mail : ";
lblY.Text = "Phone number : ";
//Add the labels and textboxes to the Panel.
Panel1.Controls.Add(lblU);
Panel1.Controls.Add(TxtBoxU);
Panel1.Controls.Add(TxtBoxU);
Panel1.Controls.Add(lblE);
Panel1.Controls.Add(TxtBoxE);
Panel1.Controls.Add(lblY);
Panel1.Controls.Add(TxtBoxY);
Panel1.Controls.Add(new LiteralControl("<br>"));
}
protected int TotalNumberAdded
{
get { return (int)(ViewState["TotalNumberAdded"] ?? 0); }
set { ViewState["TotalNumberAdded"] = value; }
}
Your problem is in your page load, becouse your click event declaretion is redundant, you are attaching the EventHandler when you are assinging by HTML, And If you push click the event, It is fires 2 time.
Remove
Button1.Click += new EventHandler(Button1_Click);
And you page load will looks like:
protected void Page_Load(object sender, EventArgs e)
{
// Add any controls that have been previously added dynamically
for (int i = 0; i < TotalNumberAdded; i++)
{
AddControls(i + 1);
}
}
I hope that help.
P.S: I'm sorry in my first test I did not test right.
protected void Button1_Click(object sender, EventArgs e)
{
TextBox txtobj = new TextBox();
Form.Controls.Add(txtobj);
txtobj.Text = "Dynamically Textbox";
}

Categories