I'm new at ASP.NET but something that continuously gives me trouble is finding nested server controls, especially when they are nested.
In this case, here is my registration page up until the server control I want:
<asp:CreateUserWizard runat="server" ID="RegisterUser" ViewStateMode="Disabled" OnCreatedUser="RegisterUser_CreatedUser">
<LayoutTemplate>
<asp:PlaceHolder runat="server" ID="wizardStepPlaceholder" />
<asp:PlaceHolder runat="server" ID="navigationPlaceholder" />
</LayoutTemplate>
<WizardSteps>
<asp:CreateUserWizardStep runat="server" ID="RegisterUserWizardStep">
<ContentTemplate>
<fieldset>
<ol>
<li>
<asp:TextBox runat="server" ID="firstName" />
</li>
For readability sake, the only things I've removed are some HTML elements. I am trying to access'firstName'. I've tried all of the following with no luck, (TextBox first is always coming up null).
TextBox first = (TextBox)Page.Master.FindControl("MainContent").FindControl("firstName");
TextBox first = (TextBox)Page.FindControl("firstName");
TextBox first = (TextBox)RegisterUserWizardStep.FindControl("firstName");
TextBox first = (TextBox)RegisterUser.FindControl("firstName");
Would appreciate help, thanks!
Often times you may need to do a recursive control search. First, add this method to your page:
private Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id)
return Root;
foreach (Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null)
return FoundCtl;
}
return null;
}
Now, to find the control, call:
TextBox firstName = (TextBox)FindControlRecursive(this, "firstName");
Try this piece of code:
TextBox first = (TextBox) RegisterUser.CreateUserStep.ContentTemplateContainer.FindControl("firstName");
Related
I have a function in the C# code behind of a Sitecore sublayout that returns a string that looks like this:
public string getProductTitle()
{
Item productItem = itemHelper.GetItemByPath(currentItemPath);
Sitecore.Data.Fields.ImageField imgField = ((Sitecore.Data.Fields.ImageField)productItem.Fields["Logo"]);
if (imgField.Value != "")
{
return "<sc:Image CssClass=\"product-image ng-scope\" Field=\"Logo\" runat=\"server\" />";
}
string productTitle = "";
productTitle = productItem["Produkt Titel"];
return "<div class=\"product-name ng-binding ng-scopen\" ng-if=\"!currentProduct.imageNameHome\">" + productTitle + "</div>";
}
And in the ascx I call this fuction:
<%= getProductTitle() %>
The problem is that in the end this is what I'm getting in HTML at runtime:
"<sc:Image CssClass=\"product-image ng-scope\" Field=\"Logo\" runat=\"server\" >";
The / at the end is missing, which breaks the whole line and no image is shown. The
I also tried this:
string a = WebUtility.HtmlEncode("<sc:Image CssClass=\"product-image ng-scopen\" Field=\"Logo\" runat=\"server\" />");
return WebUtility.HtmlDecode(a);
and this:
return #"<sc:Image CssClass=""product-image ng-scopen"" Field=""Logo"" runat=""server"" />";
With the same result.
Am I missing something here? How can I fix this?
I cannot see this working due to the ASP.NET page life cycle.
Sitecore controls are like normal user controls and they run on the server side - returning them as a string will be too late in the page lifecycle for them to render.
I would place the <sc:Image /> control in the ascx page or use a FieldRenderer object to get the HTML from Sitecore
Sitecore.Web.UI.WebControls.FieldRenderer.Render(myItem, "MyFieldName", "disable-web-editing=true");
You can then use logic to show or hide the Image Field and title control based on you requirements. This assumes you are using the Sitecore Context Item.
Replace the <%= getProductTitle() %> with
<sc:Image runat="server" ID="imgLogo" Field="Logo" />
<asp:Placeholder runat="server" ID="phTitle">
<div class=\"product-name ng-binding ng-scopen\" ng-if=\"!currentProduct.imageNameHome><sc:Text runat="server" ID="title" Field="Produkt Titel"/></div>
</asp:Placeholder>
Then in the code behind Page Load method
var currentItem = Sitecore.Context.Item;
if(string.IsNullOrEmpty(currentItem["Logo"])
{
imgLogo.Visible=False;
}
if(string.IsNullOrEmpty(currentItem["Produkt Titel"])
{
phTitle.Visible=False;
}
More information here:
http://gettingtoknowsitecore.blogspot.co.uk/2010/01/displaying-field-values-using-server.html
Since you have two alternate ways you wish to present your information, I would consider moving your controls and HTML to your markup file (ASCX) and then wrapping the segments in asp:placeholder controls.
<asp:placeholder id="imageTitle" runat="server" Visible="false">
<sc:Image CssClass="product-image ng-scope" Field="Logo" runat="server" />
</asp:placeholder>
<asp:placeholder id="textTitle" runat="server>
<div class="product-name ng-binding ng-scopen" ng-if="!currentProduct.imageNameHome">
<asp:Literal id="productTitleLiteral" runat="server" />
</div>;
</asp:placeholder>
You can then toggle the visibility of the placeholder in your code behind during page load.
public void Page_Load{
Item productItem = itemHelper.GetItemByPath(currentItemPath);
Sitecore.Data.Fields.ImageField imgField = ((Sitecore.Data.Fields.ImageField)productItem.Fields["Logo"]);
if (imgField.Value != "")
{
this.imageTitle.Visible = true;
this.textTitle.Visible = false;
}
else {
this.imageTitle.Visible = false;
this.textTitle.Visible = true;
this.productTitleLiteral.Text = productItem["Produkt Titel"];
}
}
This will allow you to ensure proper encapsulation of business logic versus presentation markup, and will work better with the .NET lifecycle.
I am doing a simple web site using asp.net and i am having troubles finding my or objects by id in the code behind in c#. I have something like this:
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
the rest is irrelevant, and then i use this in the code behind:
Table table = (Table)FindControl("camas");
i also tried:
Table table = (Table)camas;
and
Control table= (Table)FindControl("camas");
and each one of this lines gives me Null. am i doing something wrong ?
EDIT: From your answers i did this:
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
and tried all the things stated above. same result.
EDIT2: Whole Code:
C#
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControl("camas");
HiddenField NCamasHF = (HiddenField)FindControl("NCamas");
int NCamas = Convert.ToInt32(NCamasHF);
HiddenField NColunasHF = (HiddenField)FindControl("NColunas");
HiddenField CorMasc = (HiddenField)FindControl("CorMasc");
HiddenField CorFem = (HiddenField)FindControl("CorFem");
int NColunas = Convert.ToInt32(NColunasHF);
TableRow Firstrow = new TableRow();
table.Rows.Add(Firstrow);
for (int i = 1; i <= NCamas; i++)
{
if (i % NColunas == 0)
{
TableRow row = new TableRow();
table.Rows.Add(row);
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
row.Cells.Add(cell);
}
else
{
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
Firstrow.Cells.Add(cell);
}
}
}
asp.net
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:SqlDataSource
ID="ParametrosBD"
ConnectionString ="<%$ ConnectionStrings:principal %>"
ProviderName = "System.Data.SqlClient"
SelectCommand = "SELECT par_Id, par_NCamas, par_NColunas, par_CorMasculino, par_CorFeminino FROM Parametros WHERE par_Id=1"
runat="server">
</asp:SqlDataSource>
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
<ItemTemplate>
<asp:HiddenField ID="NCamas" runat="server" Value='<%# Bind("par_NCamas") %>' />
<asp:HiddenField ID="NColunas" runat="server" Value='<%# Bind("par_NColunas") %>' />
<asp:HiddenField ID="CorMasc" runat="server" Value='<%# Bind("par_CorMasculino") %>' />
<asp:HiddenField ID="CorFem" runat="server" Value='<%# Bind("par_CorFeminino") %>' />
<tr id="cama"></tr>
</ItemTemplate>
</asp:ListView>
</asp:Content>
To expand on #Yura Zaletskyy's recursive find control method from MSDN -- you can also use the Page itself as the containing control to begin your recursive search for that elusive table control (which can be maddening, I know, I've been there.) Here is a bit more direction which may help.
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControlRecursive(Page, "camas");
if (table != null)
{
//Do awesome things.
}
}
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
}
As you already added runat="server" is step 1. The second step is to find control by id, but you need to do it recursively. For example consider following function:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
None of the existing answers mention the obvious built-in solution, FindControl.
Detailed here, FindControl is a function that takes as a string the id of a control that is a child of the calling Control, returning it if it exists or null if it doesn't.
The cool thing is that you can always call it from the Page control which will look through all controls in the page. See below for an example.
var myTextboxControl = (TextBox)Page.FindControl("myTextboxControlID);
if (myTextboxControl != null) {
myTextboxControl.Text = "Something";
}
Note that the returned object is a generic Control, so you'll need to cast it before you can use specific features like .Text above.
You need to have runat="server" for you to be able to see it in the codebehind.
e.g.
<table id="camas" runat="server">
Ok. You have the table within a list view template. You will never find the control directly on server side.
What you need to do is find control within the items of list.Items array or within the item data bound event.
Take a look at this one- how to find control in ItemTemplate of the ListView from code behind of the usercontrol page?
When you're using a master page, then this code should work for you
Note that you're looking for htmlTable and not asp:Table.
// add the namespace
using System.Web.UI.HtmlControls;
// change the name of the place holder to the one you're using
HtmlTable tbl = this.Master.FindControl("ContentPlaceHolder1").FindControl("camas") as HtmlTable;
Best,
Benny
You need to add runat server like previously stated, but the ID will change based on ListView row. You can add clientidmode="Static" to your table if you expect only 1 table and find using InternamentosListView.FindControl("camas"); otherwise, you will need to add ItemDataBound event.
<asp:ListView ID="InternamentosListView" runat="server" DataSourceID="InternamentosBD" OnItemDataBound="InternamentosListView_ItemDataBound">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
You will need to introduce in code behind
InternamentosListView_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Table tdcamas = (Table)e.Item.FindControl("camas");
}
}
I have a listview control which is populated with data from a database. I have used the label to display that data. Now I need to use the value of that label in some other place. I am trying to access the text value of the label control but it says
Object reference not set to an instance of an object.
But I do have value in the label.
<asp:ListView ID="msg_list" runat="server">
<ItemTemplate>
<table>
<tr class="myitem">
<td>
<asp:Label ID="reg_id_reply" runat="server" Text="helo" Visible="false" />
<asp:Label role="menuitem" ID="msg_lbl" runat="server" text='<%#Eval("msg")%>' /><i style=" color:Gray; " > from
<asp:Label ID="tme" runat="server" Text='<%#Eval("name")%>' />
<i> on </i>
<asp:Label ID="tmelbl" runat="server" Text='<%#Eval("tme")%>'/>
<a id="msg-reply" class="btn button" data-toggle="modal" data-target="#msg-rply" style="cursor:pointer;" ><i class="glyphicon glyphicon-share-alt white"> </i></a> </td>
<hr style=" margin-top:1px; margin-bottom:1px; " />
</tr>
</table>
<%--<hr style=" margin-top:1px; margin-bottom:1px; " />--%>
</ItemTemplate>
</asp:ListView>
This is how i tried to access the text of the label.Note that the code below is inside a button click event onClick of buttom.
Label mylbl = (Label)msg_list.FindControl("reg_id_reply");
string rid = mylbl.Text;
According to the description for Control.FindControl Method (String):
This method will find a control only if the control is directly contained by the specified container.
The direct container that your label is contained within is the ItemTemplate. Therefore you may need to build a recursive search for your label if you are starting with the listview. You could try the following code that is suggested from this MSDN page:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
However also note that the listview may change the id values of components in the item template. If you know the item index you want then you can use the method suggested in this post:
var theLabel = this.ChatListView.Items[<item_index>].FindControl("reg_id_reply") as Label;
All the ways I can think to do this seem very hackish. What is the right way to do this, or at least most common?
I am retrieving a set of images from a LINQ-to-SQL query and databinding it and some other data to a repeater. I need to add a textbox to each item in the repeater that will let the user change the title of each image, very similar to Flickr.
How do I access the textboxes in the repeater control and know which image that textbox belongs to?
Here is what the repeater control would look like, with a submit button which would update all the image rows in Linq-to-SQL:
alt text http://casonclagg.com/layout.jpg
Edit:
This code works
Just make sure you don't blow your values away by Binding outside of if(!Page.IsPostBack) like me.. Oops.
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div class="itemBox">
<div class="imgclass">
<a title='<%# Eval("Name") %>' href='<%# Eval("Path") %>' rel="gallery">
<img alt='<%# Eval("Name") %>' src='<%# Eval("Path") %>' width="260" />
</a>
</div>
<asp:TextBox ID="TextBox1" Width="230px" runat="server"></asp:TextBox>
</div>
</ItemTemplate>
</asp:Repeater>
And Submit Click:
protected void Button1_Click(object sender, EventArgs e)
{
foreach (RepeaterItem item in Repeater1.Items)
{
TextBox txtName = (TextBox)item.FindControl("TextBox1");
if (txtName != null)
{
string val = txtName.Text;
//do something with val
}
}
}
Have you tried something like following on the button click:-
foreach (RepeaterItem item in Repeater1.Items)
{
TextBox txtName= (TextBox)item.FindControl("txtName");
if(txtName!=null)
{
//do something with txtName.Text
}
Image img= (Image)item.FindControl("Img");
if(img!=null)
{
//do something with img
}
}
/* Where txtName and Img are the Ids of the textbox and the image controls respectively in the repeater.*/
Hope this helps.
.aspx
<asp:Repeater ID="rpt" runat="server" EnableViewState="False">
<ItemTemplate>
<asp:TextBox ID="txtQty" runat="server" />
</ItemTemplate>
</asp:Repeater>
.cs
foreach (RepeaterItem rptItem in rpt.Items)
{
TextBox txtQty = (TextBox)rptItem.FindControl("txtQty");
if (txtQty != null) { Response.Write(txtQty.Text); }
}
Be sure to add EnableViewState="False" to your repeater, otherwise you will get empty string. (That wasted my time, dont waste yours :) )
On postback, you can iterate over the collection of RepeaterItems in repeater.Items. You could then retrieve each TextBox with code such as
TextBox tbDemo = (TextBox)rptr.Items[index].FindControl("textBox");
I'm attempting to iterate over the ListViewDataItems in an ASP.Net ListView, and use the ListView.ExtractItemValues to get the values from DataBoundControls. This works fine with ITextControls, but I am having difficulty getting the Selected Item from a RadioButtonList.
Here is my markup:
<asp:ListView ID="lvQuiz" runat="server">
<LayoutTemplate>
<fieldset>
<ul>
<asp:PlaceHolder ID="itemplaceholder" runat="server"></asp:PlaceHolder>
</ul>
</fieldset>
<asp:Button ID="cmdSubmit" runat="server" Text="Submit" OnClick="cmdSubmit_Click" />
</LayoutTemplate>
<ItemTemplate>
<li>
<fieldset>
<legend>
<asp:Label ID="lblQuestionText" runat="server" Text='<%# Bind("Question.QuestionText") %>' />
</legend>
<asp:RadioButtonList ID="rblResponse" runat="server" DataTextField="ResponseText" DataValueField="Id"
DataSource='<%# Bind("Question.PossibleResponses") %>'>
</asp:RadioButtonList>
</fieldset>
</li>
</ItemTemplate>
And here is the code where I am trying to extract the values:
var Q = (Quiz)Session["Quiz"];
foreach (var item in lvQuiz.Items)
{
var itemValues = new OrderedDictionary();
lvQuiz.ExtractItemValues(itemValues, item, true);
var myQuestion = Q.UserResponses.Keys
.Where(x => x.QuestionText == itemValues["Question.QuestionText"])
.Single();
Q.UserResponses[myQuestion] = itemValues["Question.PossibleResponses"].SelectedItem
}
My problem lies with that last line there. "Question.PossibleResponses" is bound to the RadioButtonList, but the value for itemValues["Question.PossibleResponses"] returns a list of ALL my RadioButtonList's options. How do I tell which one the user selected?
Well, I ended up implementing an extension method for Control that implements a Recursive FindControl, as outlined in Steve Smith blog post on Recursive FindControl. As I only had two bindable controls that I cared about (Label and a ListControl), this ended up being good enough. Tightly coupled to the UI, but I don't know what else to do.