Very simple but I can't figure out why it wont works.
I got five TextBox and one Button, click to count the number of TextBox.
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Testing._Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<asp:Label ID="Label1" runat="server" Text="Test"></asp:Label> </br>
<asp:TextBox ID="TextBox1" runat="server" Width="40px"></asp:TextBox>
<asp:TextBox ID="TextBox2" runat="server" Width="40px"></asp:TextBox>
<asp:TextBox ID="TextBox3" runat="server" Width="40px"></asp:TextBox>
<asp:TextBox ID="TextBox4" runat="server" Width="40px"></asp:TextBox>
<asp:TextBox ID="TextBox5" runat="server" Width="40px"></asp:TextBox>
</br>
<asp:Button ID="Button1" runat="server" Text="Generate" OnClick="Button1_Click" />
</asp:Content>
Code behind
protected void Button1_Click(object sender, EventArgs e)
{
var List = this.Controls.OfType<TextBox>();
Label1.Text = List.Count().ToString();
}
But the result return me 0.
Since your TextBoxes are inside a ContentPlaceHolder so you need to replace the this keyword with your ContentPlaceHolder(MainContent). This should works as you want:
var List = (Page.Master.FindControl("MainContent") as ContentPlaceHolder)
.Controls.OfType<TextBox>();
Label1.Text = List.Count().ToString();
Most solutions will not work if text boxes are in tables or divs. The only way is to recursively look for them in all controls. Paste the following function in a class somewhere.
public static List<Control> GetAllControls(List<Control> controls, Type t, Control parent) //first call pass this.Page as the 'Parent' parameter
{
foreach (Control c in parent.Controls)
{
if (c.GetType() == t)
controls.Add(c);
if (c.HasControls())
controls = GetAllControls(controls, t, c);
}
return controls;
}
Then from your asp page you call it as follows.
List<Control> list = new List<Control>();
list = GetAllControls(list, typeof(TextBox), this.Page);
This gets all controls of the type you passed (in my example it was TextBox)
Then you can iterate through the list of Textbox controls.
foreach (Control ctl in list)
{
if (ctl.GetType() == typeof(TextBox)) //this should always test true but you i left it here for clarity
{
//do something
((TextBox)ctl).Attributes.Add("onfocus", "this.select()");
}
}
Here is my implementation to add the select() attribute to all text boxes.
//my asp page
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
Utils.SetTextBoxFocusSelect(this.Page);
}
//in a utilities class
public class Utils
{
public static void SetTextBoxFocusSelect(Page page)
{
List<Control> list = new List<Control>();
list = GetAllControls(list, typeof(TextBox), page);
foreach (Control ctl in list)
{
if (ctl.GetType() == typeof(TextBox))
{
((TextBox)ctl).Attributes.Add("onfocus", "this.select()");
}
}
}
public static List<Control> GetAllControls(List<Control> controls, Type t, Control parent /* can be Page */)
{
foreach (Control c in parent.Controls)
{
if (c.GetType() == t)
controls.Add(c);
if (c.HasControls())
controls = GetAllControls(controls, t, c);
}
return controls;
}
}
Related
I have a two listboxes and a button. I need to add selected item from one listbox to another with click of button.
and here is the code of the button
protected void ASPxButton4_Click(object sender, EventArgs e)
{
if (listBoxSubeKiyaslama1.SelectedIndex > -1)
{
listBoxSubeKiyaslama2.Items.Add(listBoxSubeKiyaslama1.SelectedItem);
listBoxSubeKiyaslama2.Items.RemoveAt(listBoxSubeKiyaslama1.SelectedIndex);
listBoxSubeKiyaslama2.UnselectAll();
}
}
when I click the button, I see that listBoxSubeKiyaslama1.SelectedIndex is always "-1". because I think it postbacks and clears items from the first listbox. How can I fix this?
Can you try the below code:
if (listBoxSubeKiyaslama1.SelectedItem != null)
{
listBoxSubeKiyaslama2.Items.Add(listBoxSubeKiyaslama1.SelectedItem);
listBoxSubeKiyaslama2.Items.RemoveAt(listBoxSubeKiyaslama1.SelectedIndex);
listBoxSubeKiyaslama2.UnselectAll();
}
The controls will be not save the values on postbacks if EnableViewState = false. By default it is true. Please make sure you are not setting it to false.
I also suggest you to put your control in UpdatePanel to avoid full postback.
Like:
<asp:UpdatePanel ID="up1" runat="Server">
<ContentTemplate>
<asp:ListBox ID="listBoxSubeKiyaslama1" runat="server">
</asp:ListBox>
<asp:ListBox ID="listBoxSubeKiyaslama2" runat="server">
</asp:ListBox>
</ContentTemplate>
</asp:UpdatePanel>
Try the following code:-
ASPX.CS
public string GetSelectedItems(ListBox control)
{
var items = new StringBuilder();
foreach (ListItem item in control.Items)
{
if (item.Selected)
items.Append(string.Format("{0},", item.Value));
}
return items.ToString().Trim().TrimEnd(',');
}
protected void btnMoveRight_Click(object sender, EventArgs e)
{
for (int i = lbCourses1.Items.Count - 1; i >= 0; i--)
{
if (lbCourses1.Items[i].Selected == true)
{
lbCourses2.Items.Add(lbCourses1.Items[i]);
ListItem li = lbCourses1.Items[i];
lbCourses1.Items.Remove(li);
}
}
}
protected void btnMoveLeft_Click(object sender, EventArgs e)
{
for (int i = lbCourses2.Items.Count - 1; i >= 0; i--)
{
if (lbCourses2.Items[i].Selected == true)
{
lbCourses1.Items.Add(lbCourses2.Items[i]);
ListItem li = lbCourses2.Items[i];
lbCourses2.Items.Remove(li);
}
}
}
var selectedValues = GetSelectedItems(lb2);
ASPX
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div>
<asp:Label ID="lbl1" runat="server" Text="lbl1:"></asp:Label>
<asp:ListBox ID="lb1" runat="server" SelectionMode="Multiple"></asp:ListBox>
<asp:Button Runat="server" ID="btnMoveRight" Text=">>"
onclick="btnMoveRight_Click"></asp:Button>
<asp:Button Runat="server" ID="btnMoveLeft" Text="<<"
onclick="btnMoveLeft_Click"></asp:Button>
<asp:ListBox ID="lb2" runat="server" SelectionMode="Multiple"></asp:ListBox>
</div>
</ContentTemplate>
</asp:UpdatePanel>
I have a multiview inside a formview:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:FormView ID="fvSpec" runat="server" DataKeyNames="ID" OnItemUpdating="fvSpec_ItemUpdating"
OnItemInserting="fvSpec_ItemInserting" OnModeChanging="fvSpec_ModeChanging">
<EditItemTemplate>
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View ID="View1" runat="server">
<asp:DropDownList ID="ddlEditProdType" runat="server" SelectedValue='<%# Bind("CommonID") %>'></asp:DropDownList>
When switching to edit mode, the dropdownlist need to be bound:
protected void fvSpec_ModeChanging(object sender, FormViewModeEventArgs e)
{
int tableID = int.Parse(ddlItems.SelectedValue);
switch (e.NewMode)
{
case FormViewMode.Edit:
fvSpec.ChangeMode(FormViewMode.Edit);
FillEditLists();
BindFormView(tableID);
}
}
private void FillEditLists()
{
MultiView MultiView1 = (MultiView)fvSpec.FindControl("MultiView1");
View View1 = (View)MultiView1.FindControl("View1");
//ddlEditProdType COMES BACK NULL
DropDownList ddlEditProdType = (DropDownList)View1.FindControl("ddlEditProdType");
//bind ddl here
}
The formview control is found just fine.
The multiview control is found just fine.
The view control is found just fine.
But when the dropdownlist line is executed, it comes back NULL.
(object ref error)
Any input is appreciated.
Have you tried something like this:
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
Comes from this CodingHorror article. I'm kind of surprised we're on .NET 4.0 and Microsoft hasn't built something like this in yet...I use it a lot.
Found out why it was not finding the control.
The formview needed to be bound first, then find that certain control.
BindFormView(tableID);
FillEditLists();
I can't seem to figure this one out but I'm trying to add a user control to a DataList at runtime (because the actual control type can differ). So if I hard code the control reference in the markup like this it works:
<asp:DataList ID="myDL" runat="server" RepeatDirection="Horizontal" RepeatColumns="3" OnItemDataBound="myDL_Item_Bound">
<ItemTemplate>
<prefix:MyControl ID="myControl1" runat="server" />
</ItemTemplate>
</asp:DataList>
But if I try to add it programmatically to a placeholder, it does not render the user controls (just empty td tags):
<asp:DataList ID="myDL" runat="server" RepeatDirection="Horizontal" RepeatColumns="3" OnItemDataBound="myDL_Item_Bound">
<ItemTemplate>
<asp:PlaceHolder ID="ph" runat="server">
</asp:PlaceHolder>
</ItemTemplate>
</asp:DataList>
protected void myDL_Item_Bound(Object sender, DataListItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
PlaceHolder ph = (PlaceHolder)e.Item.FindControl("ph");
if (ph != null) {
MyControl ctrl = new MyControl();
ctrl.SomeProp = "xyz";
ph.Controls.Add(ctrl);
}
else {
MyControl ctrl = (MyControl)e.Item.FindControl("myControl1");
ctrl.SomeProp = "xyz";
}
}
}
what am I missing?
You are not adding the control to the page. You need to add it:
Control ctrl = (Control)Page.LoadControl("MyControl.ascx");
// MyControl ctrl = new MyControl();
ctrl.SomeProp = "xyz";
ph.Controls.Add(ctrl);
I want to know how to Add a UserControl Conditionally to a Repeater Control. I have tried to add it to the placeholder which is in Repeater Control but unable to load the usercontrol. This following code doesn't work.
<asp:Repeater ID="ResultsRepeater" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<div>
<asp:PlaceHolder ID="PlaceHolder1" runat="server">
</asp:PlaceHolder>
</div>
</ItemTemplate>
</asp:Repeater>
public void GetStatus(int i)
{
UserControl uc = new UserControl();
if(i==1)
{
uc = LoadControl("DraftList.ascx") as UserControl;
}
else if(i==2)
{
uc = LoadControl("FinalList.ascx") as UserControl;
}
PlaceHolder p1 = (PlaceHolder)ResultsRepeater.Items[0].FindControl("PlaceHolder1");
p1.Controls.Add(uc);
}
Is there some reason that you don't want to just handle all of this in the aspx? That would be the simplest and cleanest option:
<asp:Repeater runat="server" ID="ResultsRepeater">
<ItemTemplate>
<uc1:DraftList ID="DraftList1" runat="server" Visible='<%# ((int)Eval("Status") == 1)%>' />
<uc2:FinalList ID="FinalList1" runat="server" Visible='<%# ((int)Eval("Status") == 2)%>' />
</ItemTemplate>
</asp:Repeater>
If a control is not visible, (i.e., Visible=false) then no markup is rendered, so coding in this fashion would not create any more work for the server or the client browser, while having the benefit of being much easier to read and providing user control properties at design-time.
You would just need to make sure to register your controls at the top of the page:
<%# Register src="DraftList.ascx" tagname="DraftList" tagprefix="uc1" %>
<%# Register src="FinalList.ascx" tagname="FinalList" tagprefix="uc2" %>
Why don't you try adding it within the repeaters ItemDataBound event? I.e.,
<asp:Repeater ID="ResultsRepeater" OnItemDataBound="ResultsRepeater_ItemDataBound" runat="server">
<HeaderTemplate></HeaderTemplate>
<ItemTemplate>
<div>
<asp:PlaceHolder ID="PlaceHolder1" runat="server">
</asp:PlaceHolder>
</div>
</ItemTemplate>
</asp:Repeater>
and in the code behind
protected void ResultsRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Panel PlaceHolder1 = (Panel)e.Item.FindControl("PlaceHolder1");
// declare/obtain the value of i given the DataItem
// e.g.,
int i = ((int)e.Item.DataItem); // or however you're getting i
if (i == 1)
{
var uc = LoadControl("~/DraftList.ascx");
PlaceHolder1.Controls.Add(uc);
}
else if (i == 2)
{
var uc = LoadControl("~/FinalList.ascx");
PlaceHolder1.Controls.Add(uc);
}
}
}
Judging by your last comment (to the question) you might need to also make sure you've attached and bound your datasource to the repeater as well. I.e.,
ResultsRepeater.DataSource = dataSource; //whatever your datasource is e.g., datatable, IEnumerable list etc
ResultsRepeater.DataBind();
This question already has answers here:
Better way to find control in ASP.NET
(9 answers)
Closed 4 years ago.
I'm sorry, but I can't understand why this doesn't work. After compile, I receive a "Null reference exception". Please help.
public partial class labs_test : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
if (TextBox1.Text != "")
{
Label Label1 = (Label)Master.FindControl("Label1");
Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label Label1 = (Label)Master.FindControl("Label1");
Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
}
}
and UI:
<%# Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="labs_test" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
Type in text and then click button to display text in a Label that is in the MasterPage.<br />
This is done using FindControl.<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" /><br />
<br />
Choose an item from the below list and it will be displayed in the Label that is
in the MasterPage.<br />
This is done using FindControl.<br />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem>Item 1</asp:ListItem>
<asp:ListItem>Item 2</asp:ListItem>
<asp:ListItem>Item 3</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</asp:Content>
Courtesy of Mr. Atwood himself, here's a recursive version of the method. I would also recommend testing for null on the control and I included how you can change the code to do that as well.
protected void Button1_Click(object sender, EventArgs e)
{
if (TextBox1.Text != "")
{
Label Label1 = FindControlRecursive(Page, "Label1") as Label;
if(Label1 != null)
Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
Label Label1 = FindControlRecursive(Page, "Label1") as Label;
if (Label1 != null)
Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
}
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id) return root;
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null) return t;
}
return null;
}
When Label1 exists on the master page:
How about telling the content page where your master page is
<%# MasterType VirtualPath="~/MasterPages/PublicUI.Master" %>
Then making a method in the master like
public void SetMessage(string message)
{
Label1.Text = message;
}
And call it in page's code behind.
Master.SetMessage("<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>");
When Label1 exists on the content page
If it is simply on the same page, just call Label1.Text = someString;
or if you for some reason need to use FindControl, change your Master.FindControl to FindControl
FindControl only searches in the immediate children (technically to the next NamingContainer), not the entire control tree. Since Label1 is not an immediate child of Master, Master.FindControl won't locate it. Instead, you either need to do FindControl on the immediate parent control, or do a recursive control search:
private Control FindControlRecursive(Control ctrl, string id)
{
if(ctrl.ID == id)
{
return ctrl;
}
foreach (Control child in ctrl.Controls)
{
Control t = FindControlRecursive(child, id);
if (t != null)
{
return t;
}
}
return null;
}
(Note this is convenient as an extension method).