How to find all textboxes in a gridview row? - c#

I have a GridView on a website, that have different controls in each row (eg.: textbox, label, dropdownlist). I need to find all textboxes and set the enabled property to false, so the user won't be able to edit them. I tried the code below, but it dosn't work, 'c' never recognised as a textbox, so it never changes the property.
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (a)
{
foreach (Control c in e.Row.Controls)
{
if (c is TextBox)
{
((TextBox)(c)).Enabled = false;
}
}
}
}

I think you should try like this:
TextBox tb = e.Row.FindControl("textbox_name") as TextBox;
tb.Enabled = false;

Your textboxes must be nested within other controls, most likely cells inside the row. That is why you cannot find them just iterating through immediate children.
If you have a list of IDs of the text boxes, you should use FindControl:
((TextBox)e.Row.FindControl("TextBoxID")).Enabled = false;
Otherwise you will need to recursively find your controls of necessary type. See this thread for code sample.
One more option, if a is relatively easy to calculate, is to use in the markup directly, like so:
<asp:TextBox ... Enabled='<%# a %>' />
This depends a lot on the details of how a is derived. If it is a protected or public field of the page class, just the code above should work. If it is calculated based on row, you may need to turn it into protected method and pass params into it:
Enabled='<%# GetEnabled(Eval("Prop1"), Eval("Prop2")) %>'

And also want to put some updation.
There are different types of rows in gridview (header,footer,datarow,etc)
so for making little faster for the control find.
Try below (check the if condition)
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Find the TextBox control.
TextBox txtName = (e.Row.FindControl("txtName") as TextBox);
txtName.Enabled = false;
//or
TextBox txtName1 = (TextBox)e.Row.FindControl("txtName");
txtName1.Enabled = false;
}
}

You should search controls inside the cell instead of Row.
foreach (TableCell cell in e.Row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is TextBox)
{
((TextBox)(c)).Enabled = false;
}
}
}

Related

Looping through Insert Template in Formview to Obtain Controls Id returns nothing

I have a formview with some textboxes. The value of these textboxes need to be encrypted at the time of item inserting before saving into the db table.
I have been trying the below code with various variations with out any luck. It doent return anything or ends up with object reference null message.
protected void formview1_iteminserting(object sender, FormViewInsertEventArgs e)
{
if (FormView1.CurrentMode == FormViewMode.Insert)
{
foreach (Control c in FormView1.Controls)
{
if (c is TextBox)
{
TextBox txtBox = (TextBox)c;
Response.Write(txtBox.ID);
}
} }
In this case you could do a trick to achieve this using a loop:
Remember
If you have used the VS wizard to populate your FormView data control using a SqlDataSource then your text-box controls's ID will be look like this: [Name of Data Field] + TextBox
//auto generated by VS Wizard
<asp:TextBox Text='<%# Bind("NameText") %>' ID="NameTextBox" />
But if you have created them yourself you could still follow this rule to name your control IDs the same as above. and this is important for our trick.
Now you could simply use this code to get all of your text-box controls's value.
protected void FormView1_ItemInserting(object sender, FormViewInsertEventArgs e)
{
foreach (dynamic value in e.Values)
{
TextBox txtBox = FormView1.FindControl(value.Key + "TextBox") as TextBox;
if (txtBox != null)
{
Response.Write(txtBox.ID);
}
}
}
Note There won't be any exceptions if the control not found because it will be automatically handled by the as operator keyword for you ;-)

Iterating through textboxes using asp.net

I am building a page with asp.net. I have a form with a table that contains TextBoxes and a submit button. When the form is submitted, I want to grab all the text that was entered into the TextBoxes and operate on them. To do this, I have the following method:
protected void Button1_Click(object sender, EventArgs e)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Control c in this.Controls)
{
if (c.GetType().Name == "TextBox")
{
TextBox tb = (TextBox)c;
sb.AppendLine(tb.Text);
}
}
Label1.Text = sb.ToString();
}
The problem with this is that the controls apparently doesn't include any of my textboxes. When I iterate through the controls and print out their names, the only one I get is "site_master." (I also tried Controls and Page.Controls instead of this.Controls).
Is there something wrong with my iterator? Is there another way in which I could iterate through all of the textboxes in the table or page? What is the best way to accomplish this?
Would it be too much to build a List<Textbox>, given you know all your textbox controls?
List<Textbox> txtBoxes = new List<Textbox>();
txtBoxes.Add(tb1);
txtBoxes.Add(tb2);
//etc..
Then you have a nice list to work with
If I knew the controls were all in a given containing control, I would simply poll the controls of that control. For example, this.Form.Controls. However, if they could be nested within other child controls, then you could recursively explore the depths from a common outer container.
private IEnumerable<T> FindControls<T>(Control parent) where T : Control
{
foreach (Control control in parent.Controls)
{
if (control is T)
yield return (T)control;
foreach (T item in FindControls<T>(control))
yield return item;
}
}
So this would allow you to retrieve all TextBox children.
List<TextBox> textBoxes = this.FindControls<TextBox>(this).ToList();
string output = string.Join(",", textBoxes.Select(tb => tb.Text));
I'm going to assume that you are using web forms ASP.NET. Typically you declare your controls on the aspx page using something similar to
<asp:TextBox ID="someId" runat="server/>
If you have done this then in your code behind your should just be able to reference the variable someId and the property Text to get/set the text in the control.
If you are building the controls dynamically on the server you should be able to stick them in a list and iterate through it. Make sure you are creating the controls and adding them to the table during the correct part of the page lifecycle. When you add them to a cell in the table you could also keep a reference to the control in a list and just enumerate through that list in your event handler.
Maybe something along the lines of (I didn't compile this so there are probably issues):
public class MyPage: Page
{
private List<TextBox> TxtBoxes = new List<TextBox>();
//registered for the preinit on the page....
public void PreInitHandler(object sender, EventArgs e)
{
for(var i = 0; i < 2; i++)
{
var txtBox = new TextBox{Id = textBox+i};
//...add cell to table and add txtBox Control
TxtBoxes.Add(txtBox);
}
}
}

Change Style of rows created by ListView in itemCreated event

When render a databound ListView I want to dynamically set the background colour of each row depending on the results, in my case Red, Orange and Green.
protected void ListView1_ItemCreated(object sender, ListViewItemEventArgs e)
{
DataRow myRow;
DataRowView myRowView;
myRowView = (DataRowView)e.Item.DataItem;
myRow = myRowView.Row;
if (myRow[2].ToString().CompareTo("") == 1)
{
// Colour coding here..
}
}
Is it possible to reach the TR tag for each row to change the style?
Many thanks,
Stefan
The TR tag would have to have runat="server" to use server-side code; however, you may be able to inject it in without that by examining the controls that are the child of the item; there's probably a Literal or LiteralControl with the HTML, and you can use string manipulation to inject...
I worked out a solution to my problem, with some good help from Brian.
I have a ListView and I added an id tag (trRow) and tag runat="server" like this:
<AlternatingItemTemplate>
<tr id="trRow" runat="server" style="background-color:#FFF8DC;">
In code behind it looks like this:
protected void ListView1_ItemCreated(object sender, ListViewItemEventArgs e)
{
DataRow myRow;
DataRowView myRowView;
myRowView = (DataRowView)e.Item.DataItem;
myRow = myRowView.Row;
System.Web.UI.HtmlControls.HtmlTableRow myTR = (System.Web.UI.HtmlControls.HtmlTableRow)e.Item.FindControl("trRow");
if (myRow[2].ToString().CompareTo("") == 1)
{
myTR.Style.Value = "background-color:#FF0000;color: #000000;";
} else
myTR.Style.Value = "background-color:#00FF00;color: #000000;";
}
Some of the logic in there is still not correct etc, just to show how I solved the issue to dynamically change the background color of each row.

ASP.Net - Loop all HTML components in the current page

I wish I could go all the elements of an ASP.Net page (HTML elements) and manipulate its text property / value. How could I do that?
I've been checking, and the property this.Page.Form.Controls apparently gets all the elements, but I would only page elements that caught the event. Does anyone have any idea.
I'll put an example of code that I'm currently studying and trying adpater for my needs.
Thanks
string x = String.Empty;
string y = String.Empty;
foreach (Control ctrl in this.Page.Form.Controls){
if (ctrl is TextBox){
x += ((TextBox)(ctrl)).ID + ((TextBox)(ctrl)).Parent + "\n";
} else {
y += ctrl.GetType().Name + ctrl.GetType().Namespace + "\n";
}
}
Obs.: I am using some components of the Telerik components.
The controls on a page are stored in a tree data structure. You could use a recursive method to do this:
private void SetText(ControlCollection controls, String textToSet)
{
foreach(Control c in controls)
{
if (c is ITextControl)
((ITextControl)c).Text = textToSet;
if (c.HasControls())
SetText(c.Controls, textToSet);
}
}
and you would call this method somewhere like let's say, in the OnPreRender Event (to make sure that you get all controls that have been added to the page) and pass the Page.Controls ControlCollection:
protected override void OnPreRenderComplete(EventArgs e)
{
base.OnPreRenderComplete(e);
SetText(Page.Controls, "new text");
}
I'll have a stab at an answer, although I'm not sure it's what you're after (see my comments to the question).
If what you want to do is to quickly handle all the TextBoxes of a form (say) in one manner, and all of its DropDownLists in another manner, then what you're looking for may be OfType
DoSomethingWithAllTextBoxes( Page.Form.Controls.OfType<TextBox>() );
DoSomethingWithAllDropDownLists( Page.Form.Controls.OfType<DropDownList>() );
private void DoSomethingWithAllTextBoxes( IEnumerable<TextBox> textboxes) {
foreach(TextBox txt in textboxes) {
txt.Text = "Modified";
}
}
If you're looking for event binding, you could run code like this one in OnInit
protected override void OnInit(EventArgs e) {
foreach(TextBox txt in Page.Form.Controls.OfType<TextBox>() ) {
txt.OnTextChanged += TextChangedEventListener;
}
base.OnInit(e);
}
Attach the elements you want to an event and then act of them when its fired. This example is for demonstration but you could define a custom event.
ASPX:
<asp:TextBox ID="TextBox1" AutoPostBack="true" runat="server"
ontextchanged="TextBox1_TextChanged"></asp:TextBox>
<asp:TextBox ID="TextBox2" AutoPostBack="true" runat="server"
ontextchanged="TextBox1_TextChanged"></asp:TextBox>
Code-Behind:
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
//do something
}

Hiding/Unhiding Control in Gridview’s column - shifting problem

This is a follow up to my previous question:
link text
In gridview's column i have a linkbutton and a label under it.
I want to hide/unhide label when linkbutton is clicked. I use javascript because i don't want any postbacks.
The code:
protected void gvwComments_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
LinkButton lButton = ((LinkButton)e.Row.Cells[2].FindControl("lbtnExpand"));
Label label = ((Label)e.Row.Cells[2].FindControl("lblBody"));
lButton.Attributes.Add("onclick", string.Format("HideLabel('{0}'); return false;", label.ClientID));
}
}
function HideLabel(button) {
var rowObj = document.getElementById(button);
if (rowObj.style.display == "none") {
rowObj.style.display = "block";
}
else {
rowObj.style.display = "none";
}
}
The problem is that when I unhide the label by clicking on button, linkbutton is shifted a a bit upper it's original position in the cell.
Is it possible to preserve linkbutton's position in the gridviews cell?
I would suggest you change your CSS from display:none to display:hidden which will hide the control but maintain the space preventing the jumping around.
The trick is to use the keyword "this" and then get a reference to the row and change the label from there.
I have a post here, where I have a GridView with a CheckBox column and a Name column. When the CheckBox is checked the background color of the Name on that row changes. I do this starting with this attribute in the CheckBox's column:
onclick="toggleSelected(this)"
then I have a JavaScript function that finds the row and changes the next cell:
function toggleSelected(sender) {
// note that at this point the "this" is now "sender" -which is the checkbox
// get a reference to the row using the helper function - see below.
var row = GetParentElementByTagName(sender, "TR");
if (sender.checked)
row.cells[1].className = "selected";
else
row.cells[1].className = '';
}
This uses the helper function:
function GetParentElementByTagName(element, tagName) {
var element = element;
while (element.tagName != tagName)
element = element.parentNode;
return element;
}
You have a slightly different requirment so you would use something like:
var lbl = row.cells[1].childNodes[0].getElementsByTagName('label')
to get a reference to your label.

Categories