I'm designing in a web form.. the idea is like to design a forum -Like Here - where there is a main post body (Like this question im writing) and there be some replies to this question (like The ones will be answered to this question).
I have problem in putting reply comments under each other
I have made a reply button, when it is pressed,this code executes:
TextBox tb = new TextBox();
Panel3.Controls.Add(tb);
which panel3 is a panel under the main body, and textBox is a field for reply comments, and i want there to be as many as text boxes in the panel3 as the button is inserted.
when i click for the 2nd or 3rd or.... times, the current text box goes over the previous one and it wont go under it
how can i position each under previous text box?
This is related to CSS or HTML issues.
The idea is to add <div> to contain the TextBox before they are added to the panel.
Below are the sample codes:
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["Counter"] = 0;
}
else
{
//Sync ViewState Info to maintain the state
List<string> texts = new List<string>();
//The dynamic textbox values are captured from Request.Form
foreach (string key in Request.Form.Keys)
{
if (key.Contains("ctrlsuper"))
{
texts.Add(Request.Form[key]);
}
}
Texts = texts;
}
}
protected void btnAdd_Click(object sender, EventArgs e)
{
//Rerender the textboxes to UI and add one more new empty textbox.
for (int i = 0; i <= Convert.ToInt32(ViewState["Counter"]); i++)
{
HtmlGenericControl div = new HtmlGenericControl("div");
TextBox tb = new TextBox();
tb.ID = "ctrlsuper" + i.ToString();
//Refresh the textbox text according to its previous value.
if (Texts.Count > 0 && i < Texts.Count)
{
tb.Text = Texts[i];
}
div.Controls.Add(tb);
pnlControls.Controls.Add(div);
}
ViewState["Counter"] = Convert.ToInt32(ViewState["Counter"]) + 1;
}
public List<string> Texts
{
get
{
if (ViewState["Texts"] == null)
{
return new List<string>();
}
else
{
return ViewState["Texts"] as List<string>;
}
}
set
{
ViewState["Texts"] = value;
}
}
}
The ASPX:
<asp:Panel runat="server" ID="pnlControls">
</asp:Panel>
<asp:Button runat="server" ID="btnAdd" Text="Add" OnClick="btnAdd_Click" />
Hope it helps.
Related
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>
I started this question and was able to get an answer to my original question. Now the textbox gets removed but only the second time I click the remove button. Here is what I have tried
protected void btnRemoveTextBox_Click(object sender, EventArgs e)
{
foreach (Control control in PlaceHolder1.Controls)
{
var tb = new TextBox();
tb.ID = "Textbox" + counter;
if ((control.ID == tb.ID.ToString()) && (control.ID != null))
{
controlIdList.Remove(tb.ID);
ViewState["controlIdList"] = controlIdList;
}
}
}
When I step through using breakpoints and error debugging the code runs through twice without error however on the second time through it removes the button.
Because you created and added textboxes in LoadViewState method (earlier in the the page's life cycle), and here only remove an id from controlIdList but not from the control tree. Note: you do not need to create new TextBox instances in btnRemoveTextBox_Click method.
protected void btnRemoveTextBox_Click(object sender, EventArgs e)
{
foreach (Control control in PlaceHolder1.Controls)
{
string id = "Textbox" + counter;
if (control.ID == id)
{
controlIdList.Remove(id);
PlaceHolder1.Controls.Remove(control);
break;
}
}
}
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;
}
as suggested in the title i have in which i can insert how many textboxes i want to add to a placeholder. i can add the textboxes just fine the problem is i cant get the values inserted on those dynamically added textboxes. here's my code
the purpose of this piece of code is to whenever the textbox in which i can introduce the number of textboxes i want. it creates and adds them to the placeholder in my page.
public void txtExtra_TextChanged(object sender, EventArgs e)
{
for (a = 1; a <= int.Parse(txtExtra.Text); a++)
{
TextBox txt = new TextBox();
txt.ID = "txtquestion" + a;
pholder.Controls.Add(txt);
}
}
this is the code of the button that will submit and response.write the values inserted in all those textboxes.
protected void btnConfirm_Click(object sender, EventArgs e)
{
foreach (Control ctr in pholder.Controls)
{
if (ctr is TextBox)
{
string value = ((TextBox)ctr).Text;
Response.Write(value);
}
}
}
i've been searching online and i've been getting answers that this code is fine and it should work but it doesnt. if you guys see anything wrong or have any suggestion that can solve my problem i'd really appreciate it
You are almost there.
Problem
You need to reload those dynamically created textboxes on post back. Otherwise, they will become null, and you won't be able to find it.
In order to do that, you need to save those dynamically TextBoxes Ids in persistent location such as View State or Session State.
Screen Shot
ASPX
Number of TextBoxes: <asp:TextBox runat="server" ID="CounterTextBox"
OnTextChanged="CounterTextBox_TextChanged" AutoPostBack="True" /><br/>
<asp:PlaceHolder runat="server" ID="TextBoxPlaceHolder" /><br/>
<asp:Button runat="server" ID="ConfirmButton" Text="Confirm"
OnClick="ConfirmButton_Click" /><br/>
Result: <asp:Literal runat="server" ID="ResultLiteral"/>
Code Behind
private List<string> TextBoxIdCollection
{
get
{
var collection = ViewState["TextBoxIdCollection"] as List<string>;
return collection ?? new List<string>();
}
set { ViewState["TextBoxIdCollection"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
foreach (string textboxId in TextBoxIdCollection)
{
var textbox = new TextBox {ID = textboxId};
TextBoxPlaceHolder.Controls.Add(textbox);
}
}
protected void CounterTextBox_TextChanged(object sender, EventArgs e)
{
var collection = new List<string>();
int total;
if (Int32.TryParse(CounterTextBox.Text, out total))
{
for (int i = 1; i <= total; i++)
{
var textbox = new TextBox { ID = "QuestionTextBox" + i };
// Collect this textbox id
collection.Add(textbox.ID);
TextBoxPlaceHolder.Controls.Add(textbox);
}
TextBoxIdCollection= collection;
}
}
protected void ConfirmButton_Click(object sender, EventArgs e)
{
foreach (Control ctr in TextBoxPlaceHolder.Controls)
{
if (ctr is TextBox)
{
string value = ((TextBox)ctr).Text;
ResultLiteral.Text += value;
}
}
}
You are actually creating textboxes with property Text set to default = ""; So you need set txt.Text property for example:
public void txtExtra_TextChanged(object sender, EventArgs e)
{
for (int a = 1; a <= int.Parse(txtExtra.Text); a++)
{
TextBox txt = new TextBox();
txt.ID = "txtquestion" + a;
txt.Text = "Some text"; // Set some text here
pholder.Controls.Add(txt);
}
}
EDIT:
After that you can store your values into the list:
private static List<string> values = new List<string>();
protected void btnConfirm_Click(object sender, EventArgs e)
{
foreach (Control ctr in pholder.Controls)
{
if (ctr is TextBox)
{
string value = ((TextBox)ctr).Text;
values.Add(value); // add values here
}
}
}
EDIT:
Here is your values:
EDIT:
For super mega better understanding:
Create one more textbox txtOutput then add button GetDataFromTextBoxesAndPutItBelow and create an event for that button `Click'. Event code:
protected void btnGetData_Click(object sender, EventArgs e)
{
for (int i = 0; i < values.Count; i++)
txtOutput.Text += "Value from txtquestion1: " + values[i] + " ";
}
Screenshot looks:
for (int i = 0; i < dataTable.Rows.Count; i++)
{
int comment_id = Convert.ToInt32(dataTable.Rows[i]["comment_id"]);
string created_by_name = dataTable.Rows[i]["created_by_name"].ToString();
string created_at = dataTable.Rows[i]["created_at"].ToString();
string comment = dataTable.Rows[i]["comment"].ToString();
HtmlGenericControl divComment = new HtmlGenericControl("div"); //This is root object of comment.Other objects like textbox,button,etc added into this object.
//divComment.Attributes.Add("class", "div_post_display");
divComment.Attributes.Add("id", comment_id.ToString());
/* Comment by */
HtmlGenericControl lblCommentBy = new HtmlGenericControl("label");
//lblCommentBy.Attributes.Add("class", "divauthor");
lblCommentBy.InnerText = "" + created_by_name + " (" + created_at + ")";
/* Comment body */
HtmlGenericControl pComment = new HtmlGenericControl("p");
//lblCommentBy.Attributes.Add("class", "divauthor");
pComment.InnerText = comment;
divComment.Controls.Add(lblCommentBy);
divComment.Controls.Add(pComment);
if (Session["user_id"] != null)
{
if (Session["user_level"].ToString() == "1") //Admin can reply for comment
{
/* Reply Form */
TextBox txtReply = new TextBox(); //Create object dynamacaly
txtReply.ID = "txtReply_"+comment_id;
txtReply.Attributes.Add("class", "form-control"); //Add css class
txtReply.Width = 400;
divComment.Controls.Add(txtReply); //Add obj to root object(div)
Button btnReply = new Button(); //Create object dynamacaly
btnReply.Text = "Reply"; //Set button text
btnReply.Attributes.Add("class", "btn btn-sm btn-success"); //Add css class
btnReply.Click += btnReply_Click;
btnReply.CommandArgument = comment_id.ToString();
divComment.Controls.Add(btnReply); //Add obj to root object(div)
HtmlGenericControl br = new HtmlGenericControl("br"); //Create object dynamacaly
divComment.Controls.Add(br); //new line
}
}
pnlShowComments.Controls.Add(divComment);
}
I am using C# on Visual Studio. I want to generate a webform with auto numbered Textboxes depending on the input from the previous page. What is the best way to do this loop?
For example:
Input is 4
The next page should generate textboxes with ID of
"name1"
"name2"
"name3"
"name4"
Something like this :
<asp:TextBox ID="name1" runat="server"></asp:TextBox>
<asp:TextBox ID="name2" runat="server"></asp:TextBox>
<asp:TextBox ID="name3" runat="server"></asp:TextBox>
<asp:TextBox ID="name4" runat="server"></asp:TextBox>
Part 2 of my question is that if I want to call them when a Button is click, how should I use a loop the get those ID?
Use for loop and PlaceHolder control to create dynamic TextBox controls
<asp:PlaceHolder ID="phDynamicTextBox" runat="server" />
int inputFromPreviousPost = 4;
for(int i = 1; i <= inputFromPreviousPost; i++)
{
TextBox t = new TextBox();
t.ID = "name" + i.ToString();
}
//on button click retrieve controls inside placeholder control
protected void Button_Click(object sender, EventArgs e)
{
foreach(Control c in phDynamicTextBox.Controls)
{
try
{
TextBox t = (TextBox)c;
// gets textbox ID property
Response.Write(t.ID);
}
catch
{
}
}
}
You could create those controls in the Page Init event handler by say loop for the number of times the control needs to made available.
Please remember since these are dynamic controls they need to be recreated during postbacks and will not be done automatically.
Further Dynamic controls and postback
Check this code.
In first page...
protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("Default.aspx?Name=" + TextBox1.Text);
}
In second page you can get the value from querystring and create controls dynamically
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["Name"] != null)
Response.Write(Request.QueryString["Name"]);
Int32 howmany = Int32.Parse(Request.QueryString["Name"]);
for (int i = 1; i < howmany + 1; i++)
{
TextBox tb = new TextBox();
tb.ID = "name" + i;
form1.Controls.Add(tb);
}
}
for ( int i=0; i<4; i++ )
{
TextBox t = new TextBox();
t.ID = "name" + i.ToString();
this.Controls.Add( t );
}