Hello i got this problem.
I have table that got rows filled with dynamically generated controls (TextBox) in first cell , button (MyCustomButton) in second and validation control in last cell (RegularExpressionValidator). The validation controller checks if data in the TextBox are correct. Function of the button is to remove row containing this button, textbox and validator.
My problem is when i click that button to remove row that it belongs to exception will pop up saying that "Unable to find control id 'MyTextBoxId' referenced by the 'ControlToValidate'".
Problem here is that validator cant find TextBox to validate because it was removed and this exception pop up. I tried to first remove this validator and after that rest of the row, clear incorrect data in TextBox, turn off validation of that TextBox but im still getting this exception even after the validator was removed.
Removing from table method
protected void DeleteMemberRow_Click(object sender, EventArgs e)
{
//Find row to remove
TableRow row = (TableRow)((MyCustomButton)sender).Parent.Parent;
//Custom list of controls - works fine
ControlsList.RemoveAll(x => x.id == row.ID.Replace("row", ""));
//MyTable is basic Table type
MyTable.Rows.Remove(row);
}
Adding table rows
Guid guid = Guid.NewGuid();
TextBox txt = new TextBox();
MyCustomButton btn = new MyCustomButton();
btn.Click += new System.EventHandler(DeleteMemberRow_Click);
btn.ID = "TeamMember" + guid + "btn";
txt.ID = "TeamMember" + guid;
RegularExpressionValidator validate = new RegularExpressionValidator();
validate.ValidationExpression = #"(\d{5}, ?)*\d{5}";
validate.ErrorMessage = "My error message";
validate.Attributes.Add("runat", "server");
validate.ControlToValidate = "TeamMember" + guid;
validate.Attributes.Add("Display", "none");
TableRow tRow = new TableRow();
tRow.ID = "Teammember" + guid + "row";
TableCell tCell2 = new TableCell();
TableCell tCell = new TableCell();
TableCell tCell1 = new TableCell();
tCell2.Controls.Add(validate);
tCell1.Controls.Add(btn);
tCell.Controls.Add(txt);
tRow.Cells.Add(tCell);
tRow.Cells.Add(tCell1);
tRow.Cells.Add(tCell2);
MyTable.Rows.Add(tRow);
Any help would be appreciated. Thank you
Ok its fixed there wasnt problem with code but with me. I didnt noticed that i got another validator checking same TextBox so after i deleted it the other one failed to find TextBox to validate.
Related
I am new to asp.net and c# and have to deal with the event handling for a dynamically created table.
The Background:
I have a method in my code-behind CSS file and there, I create dynamically a table to show users in the first column and for every user, I have a checkbox in the second column. My table is displayed well, so the creation is not the problem.
My problem is, that I need event-handling. The goal is, to "mark" users by clicking their appropriate checkbox and then to do, whatever I should do with such users.
I have added the code for event handling with "+=" and I have also tried to use an event handler object. But the problem is: my event-handling code is never reached (i checked this by running and debugging the code).
I'm totally new to asp.net and c# and HTML, javascript and so on. So i don't know much about page-life-cycle and things like that. And it will last time, to get in, cause im a student and I'm just working 2 days a week. If anybody can explain me, how I can do event handling in c# and asp.net for dynamically created elements, that would help me much. Thanks for every help :)
foreach (ListItem li in list_deletedUsers.Items)
{
String s = li.Text;
//Creating the basic Elements
TableRow myrow = new TableRow();
TableCell cellone = new TableCell();
TableCell celltwo = new TableCell();
CheckBox cb = new CheckBox();
//cb.CheckedChanged += cb_CheckedChanged;
//cb.CheckedChanged += this.cb_CheckedChanged;
//cb.CheckedChanged += new
System.EventHandler(cb_CheckedChanged);
//Setting the values and adding cells to row
cellone.Text = s;
myrow.Cells.Add(cellone);
celltwo.Controls.Add(cb);
celltwo.ApplyStyle(tableStyle);
myrow.Cells.Add(celltwo);
//Third Column Cell for further use
//TableCell cellthree = new TableCell();
//cellthree.BackColor = System.Drawing.Color.AliceBlue;
//Adding to Row
//myrow.Cells.Add(cellthree);
//Adding to TableBert
TableBert.Rows.Add(myrow);
}
Here in this methode i create the table:
public void rbe_changed(object sender, EventArgs e)
{
//do some stuff
//look for the user list
//create the table like i show above
}
I am trying to make a dynamic table which has a couple of rows and the last row is a plus button, which will add a new row. (I will only describe the important information, to keep it simple.)
I thought of this way to accomplish it:
// .aspx code
<li><asp:LinkButton ID="LM_Show" runat="server" Text="Show list" OnClick="Action"/></li>
<asp:PlaceHolder ID="infoTable" runat="server"></asp:PlaceHolder>
//CreateTable function
public void Clicked(object sender, EventArgs e){
table();
}
public void table() {
//Do stuff...
//Screen variable is keeping track of which screen should be shown in .aspx
infoTable.Controls.Add(CreateView.createTable<Employee>(screen, this.Context, table));
}
//Create the actual table
public static Table createTable<T>(Screen screen, HttpContext context, Action method) where T : new() {
//New table and make it stretch
Table tb = new Table();
tb.Width = Unit.Percentage(100);
tb.Height = Unit.Percentage(100);
//Gather list from session
List<T> items = (List<T>)context.Session["list"];
//Create table content based on the list
for (int i = 1; i <= items.Count(); i++) {
TableRow tr = new TableRow();
//Foreach property create cells with content according to the property
//Add these cells to the row
tb.Rows.Add(tr);
}
//Create 1 final row which has a button to be able to add 1 row
TableRow tr2 = new TableRow();
TableCell tc = new TableCell();
tr.Cells.Add(tc);
//Create the Button
Button button = new Button();
button.Text = "+";
//!!This is not getting triggered!!//
button.Click += (s, e) => {
List<T> tempItems = (List<T>)context.Session["list"];
tempItems.Add(new T());
context.Session["list"] = tempItems;
//When a button is pressed, it gives a postback.
//The table has to be rebuild over again with the newly added item
method();
};
//!!This is not getting triggered!!//
//Add the button
tr2.Cells[0].Controls.Add(button);
tb.Rows.Add(tr2);
return tb;
}
Any comments about the code or how to accomplish it even better are also very welcome.
This could be achieved more easily if you used jQuery AJAX and communicate with a web service/method to get the data. However, it can be achieved in C# as well. Assuming that the given below part of the code is not working,
//Add the button
tr2.Cells[0].Controls.Add(button);
tb.Rows.Add(tr2);
You can try adding button to tc first, and then add tc to the row tr
tc.Controls.Add(button);
tr2.Cells.Add(tc);
tb.Rows.Add(tr2);
Good Luck!
I have the following code :
Label docsLabel = new Label();
docsLabel = (Label)tasksPlaceholder.FindControl("taskdocs_" + taskId);
int index = tasksPlaceholder.Controls.IndexOf(docsLabel);
The label is found within the placeholder, but when I call .IndexOf() it always returns -1.
How do I find the correct position of this control?
This is an important information in your comments:
the element I want to update is 3 levels down (TableRow -> TableCell ->Label)
Control.FindControl finds all control in this NamingContainer whereas ControlCollection.IndexOf finds only controls in this control. So if this control contains for example a table which contains rows and cells and every cell contains also controls, all of these controls will not be found by IndexOf, only the top-control is searched.
Control.FindControl will search all controls that belong to this NamingContainer(a control that implements INamingContainer). A table/row/cell does not implement it, that's why all of these controls are also searched with FindControl.
However, FindControl will not search through sub-NamingContainers (like a GridView in a GridViewRow).
This reproduces your issue:
protected void Page_Init(object sender, EventArgs e)
{
// TableRow -> TableCell ->Label
var table = new Table();
var row = new TableRow();
var cell = new TableCell();
var label = new Label();
label.ID = "taskdocs_1";
cell.Controls.Add(label);
row.Cells.Add(cell);
table.Rows.Add(row);
tasksPlaceholder.Controls.Add(table);
}
protected void Page_Load(object sender, EventArgs e)
{
Label docsLabel = (Label)tasksPlaceholder.FindControl("taskdocs_1");
int index = tasksPlaceholder.Controls.IndexOf(docsLabel);
// docsLabel != null and index = -1 --> quod erat demonstrandum
}
How do I find the correct position of this control?
If you want to find the row-number this label belongs to:
Label docsLabel = (Label)tasksPlaceholder.FindControl("taskdocs_1");
TableRow row = (TableRow)docsLabel.Parent;
Table table = (Table)row.Parent;
int rowNumber = table.Rows.GetRowIndex(row);
I am creating a table of components, and need the ability to add items from a dropdown list to each item in the table. These lists are added programmatically using a foreach like this:
MyDatabase db = new MyDatabase();
if (db.ComponentTypes.Count() > 0)
{
foreach (ComponentType componentType in db.ComponentTypes)
{
// Header row components
TableRow componentRow = new TableRow();
TableCell componentTypeCell = new TableCell();
// Create Header Row
componentTypeCell.ColumnSpan = 5;
componentTypeCell.Text = componentType.Name;
componentTypeCell.Attributes.Add("style", "background: black; color: white; font-weight: bold;");
componentRow.Cells.Add(componentTypeCell);
tblRigActionTypesAndComponentTypes.Rows.Add(componentRow);
// Middle portion omitted for simplicity
//=================================================
// Relevant portion
// DDL Row Components
TableRow addActionRow = new TableRow();
TableCell rigActionTypeMenuCell = new TableCell();
TableCell addRigActionTypeButtonCell = new TableCell();
DropDownList ddlRigActionTypeMenu = new DropDownList();
Button addRigActionTypeButton = new Button();
// Populate dropdown with action types
Helper.PopulateDropdownWithActionTypes(ddlRigActionTypeMenu);
rigActionTypeMenuCell.Controls.Add(ddlRigActionTypeMenu);
addRigActionTypeButton.Text = "Add This Action";
addRigActionTypeButton.CommandName = "Add";
addRigActionTypeButton.CommandArgument = componentType.ID.ToString();
addRigActionTypeButtonCell.ColumnSpan = 4;
addRigActionTypeButtonCell.Controls.Add(addRigActionTypeButton);
addActionRow.Cells.Add(rigActionTypeMenuCell);
addActionRow.Cells.Add(addRigActionTypeButtonCell);
tblRigActionTypesAndComponentTypes.Rows.Add(addActionRow);
}
}
Button Handler
protected void ButtonHandler(object sender, EventArgs e)
{
Button button = (Button)sender;
MyDatabase db = new MyDatabase();
if (button.CommandName == "Add")
{
// How do I capture the selected value from the
// dropdown menu paired with the "add" button?
}
}
Capturing the component the button belongs to is easy using the CommandArgument property, but how can I get the corresponding DDL?
Update: Moe S' Method
I have been unable to get this to work. I have tried a few different ways to access the dropdown menu using button.NamingContainer, but keep hitting a Object reference not set to an instance of an object. error. My last attempt is below:
Control control = button.NamingContainer;
Control test = control.FindControl("ddlRigActionTypeMenu");
lblPageHeader.Text = test.UniqueID;
Update 2:
To shed some additional light on the above (non-working) code, the following DOES work:
Control control = button.NamingContainer;
lblPageHeader.Text = button.NamingContainer.UniqueID;
This changes the page header to dnn$ctr498$AssignRigActionTypesToComponentTypes
Solved
I am marking Moe as the accepted answer on this because he got me pointed in the right direction, but Parent was what ended up working for me, not NamingContainer. All of the same principles still apply though.
Solution:
DropDownList ddl = (DropDownList)((TableRow)((TableCell)button.Parent).Parent).Cells[0].Controls[0];
You should be able to use the following to access the table row:
TableRow tblRow = (TableRow) button.NamingContainer;
And then use the FindControl option to access the DropDownList
DropDownList ddlMenu = (DropDownList) tblRow.FindControl("ddlRigActionTypeMenu");
And then obviously SelectedValue to capture the value
I'm trying to make a page that loads an undefined number of rows into a table, each row containing two columns, one column a string, the other a TextBox. When I click a submit button, i want to be able to retrieve the values entered into each TextBox.
The first half i can do, obviously in the real code this would be in a foreach loop and the textbox ID assigned a unique value i could reproduce later to call it with.
TableCell myCell = new TableCell();
myCell.Text = "StudentID";
TableCell nextCell = new TableCell();
TextBox mytext = new TextBox();
mytext.ID = "TxtBox1";
nextCell.Controls.Add(mytext);
TableRow myRow = new TableRow();
myRow.Cells.Add(myCell);
myRow.Cells.Add(nextCell);
TableStuUploads.Rows.Add(myRow);
When i click my submit button, i try to run this code(just temp code ATM, proof of concept stuff):
TextBox tmptext = (TextBox)FindControl("TxtBox1");
Label1.Text = tmptext.Text;
But that sets tmptext as null, and i get a null pointer exception on the next line. So then i tried
TextBox tmptext = (TextBox)TableStuUploads.FindControl("TxtBox1");
Label1.Text = tmptext.Text;
Same error. Then i tried
foreach (Control x in TableStuUploads.Controls)
{
if (x.GetType().ToString().Equals("System.Web.UI.WebControls.TextBox"))
{
Label1.Text = ((TextBox)x).Text;
}
}
But when debugging this, I see TableStuUploads.Controls has a count of zero.
How am I supposed to address these dynamically created controls? I have searched around, and the answer i got lead me to the three solutions i have already tried. Where am i going wrong?
You are probably not recreating your dynamic controls on post back. This is required to both find each control and retrieve each control's value.
In addition, it would probably be best to use a repeater to create these controls, It is easier to maintain and debug.
Edit
You need to recreate your table on each postback(page_load) like #ShaiCohen says in his answer then you need something ilke:
foreach (TableRow item in TableStuUploads.Rows)
{
TextBox tmptext = (TextBox)item.FindControl("TxtBox1");
Label1.Text = tmptext.Text;
}