ASP.NET find control by id - c#

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");
}
}

Related

How do I find the value of a checkbox from a gridview in asp/c#

I have had the most trouble with finding the value of a checkbox. I have searched everywhere and I can't seem to get it to the right value, nothing comes up or I get a NULL reference error. I have checked the other threads/posts and none seem to work.
All I'm trying to do is get the value of a checkbox, but I can't seem to do that.
The information is coming from a database. I can grab the string value but I can't grab the checkbox value.
Anyways, this is the code I used to get ahold of the string value and checkbox value:
//String grabber
Convert.ToString(gvOrders.SelectedRow.Cells[2].Text);
//Checkbox grabber
Boolean.TryParse(gvOrders.SelectedRow.Cells[11].Text, out bool pep);
or
//Checkbox grabber
Convert.ToBoolean(gvOrders.SelectedRow.Cells[2].Text);
Anyways, please no negativity, I've been struggling to find the value and it just isn't working.
Thanks in advance.
EDIT:
ADDED CODE:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Default2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Convert.ToString(Session["username"]) != "Scott" || Convert.ToString(Session["perms"]) != "admin")
{
Response.Redirect("Default.aspx");
}
GuestOrderInfo temp = new GuestOrderInfo();
gvOrders.DataSource = temp.SearchAll();
gvOrders.DataBind();
}
protected void osicOrders(object sender, EventArgs e)
{
Int16 row = Convert.ToInt16(gvOrders.SelectedRow.Cells[1].Text);
Session["row"] = row;
//Convert to a session to use in a different function.
Session["fName"] = Convert.ToString(gvOrders.SelectedRow.Cells[2].Text);
Session["lName"] = Convert.ToString(gvOrders.SelectedRow.Cells[3].Text);
Session["street"] = Convert.ToString(gvOrders.SelectedRow.Cells[4].Text);
Session["street2"] = Convert.ToString(gvOrders.SelectedRow.Cells[5].Text);
Session["city"] = Convert.ToString(gvOrders.SelectedRow.Cells[6].Text);
Session["state"] = Convert.ToString(gvOrders.SelectedRow.Cells[7].Text);
Session["zip"] = Convert.ToString(gvOrders.SelectedRow.Cells[8].Text);
Session["price"] = Convert.ToDouble(gvOrders.SelectedRow.Cells[9].Text);
Session["size"] = Convert.ToString(gvOrders.SelectedRow.Cells[10].Text);
Session["pepperoni"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[11].Text, out bool pep);
Session["sausage"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[12].Text, out bool sau);
Session["meatball"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[13].Text, out bool mea);
Session["ham"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[14].Text, out bool hamm);
Session["peppers"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[15].Text, out bool pepp);
Session["onions"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[16].Text, out bool onio);
Session["spinach"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[17].Text, out bool spin);
Session["pineapple"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[18].Text, out bool pine);
Session["bbq"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[19].Text, out bool bbqq);
Session["xcheese"] = Boolean.TryParse(gvOrders.SelectedRow.Cells[20].Text, out bool xch);
//
//
//FIND OUT HOW TO GET THE VALUE OF A CHECKBOX IN GV AND USE THAT VALUE WITHIN SESSION VARIABLES TO UPDATE DATA IN THE UPDATE PAGE THEN MAKE A SEARCH PAGS
//
//
CheckBox cb = (CheckBox)gvOrders.SelectedRow.Cells[11].FindControl("pepperoni");
selectedID.Text = "Selected: " + Convert.ToString(row);
selectedInformation.Text = Session["fName"] + " " + Session["lName"] + " Pepp = " + cb.Checked;
edit.Visible = true;
delete.Visible = true;
selectedInformation.Visible = true;
cancel.Visible = true;
}
protected void delete_OnClick(object sender, EventArgs e)
{
string buttonText = (sender as LinkButton).Text;
if (buttonText == "Delete")
{
edit.Visible = false;
delete.Visible = false;
yes.Visible = true;
no.Visible = true;
sure.Visible = true;
}
if (buttonText == "Edit")
{
Response.Redirect("editOrders.aspx");
}
if (buttonText == "Yes")
{
GuestOrderInfo temp = new GuestOrderInfo();
temp.DeleteARecord(Convert.ToInt16(Session["row"]));
Session.Remove("row");
Response.Redirect("viewOrders.aspx");
}
if (buttonText == "No")
{
edit.Visible = true;
delete.Visible = true;
yes.Visible = false;
no.Visible = false;
sure.Visible = false;
}
if (buttonText == "Cancel")
{
Response.Redirect("viewOrders.aspx");
}
}
}
ORIGINAL HTML:
<%# Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="viewOrders.aspx.cs" Inherits="Default2" %>
<asp:Content ID="Content1" ContentPlaceHolderID="title" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="BodyContent" Runat="Server">
<asp:GridView ID="gvOrders" runat="server" OnSelectedIndexChanged="osicOrders" AutoGenerateSelectButton="True" >
</asp:GridView>
<asp:Label runat="server" ID="selectedID"></asp:Label>
<asp:Label runat="server" ID="selectedInformation" Visible="False"/>
<asp:LinkButton runat="server" ID="edit" Text="Edit" OnClick="delete_OnClick" Visible="False"/> <asp:LinkButton runat="server" ID="delete" Text="Delete" Visible="False" OnClick="delete_OnClick"/><asp:LinkButton runat="server" ID="cancel" Text="Cancel" Visible="False" OnClick="delete_OnClick"/><br/>
<asp:Label runat="server" Text="Are you sure you want to do this?" ID="sure" Visible="False"></asp:Label><br/>
<asp:LinkButton runat="server" Visible="False" ID="no" Text="No" OnClick="delete_OnClick"/> <asp:LinkButton runat="server" Visible="False" ID="yes" Text="Yes" OnClick="delete_OnClick"/>
<!-- Make the edit button work along with the delete -->
<!-- Data validation, design and submit :^) -->
</asp:Content>
If you are using a CheckBoxField in your grid view as below, then the code for getting checkbox value is as given in second code snippet.
Checkbox column markup in GridView
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
Getting the checkbox value in code-behind
bool isChecked = (gvOrders.SelectedRow.Cells[11].Controls[0] as CheckBox).Checked;
However, if you are using a template column in your gridview, then you need to follow different approach that is explained below.
In your code-behind,
you need to first get the gridview's data row
and then find the checkbox control using the ID of the checkbox
control you specified in your html markup, which is CheckBox1 in
code sample below ( you don't need to bother about getting the cell containing checkbox in this case)
Templated Checkbox Column
<asp:TemplateField HeaderText="CheckBox Column">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Eval("Discontinued") %>' />
</ItemTemplate>
Getting the checkbox value in code-behind
bool isChecked = (gvOrders.SelectedRow.FindControl("CheckBox1") as CheckBox).Checked;
It's not clear what value you want to return from the CheckBox. Do you want to get the Checkbox label or selection status?
Anyway instead of trying to get the cell content directly, I think you should instead find the checkbox control like this.
CheckBox cb = (CheckBox)gvOrders.SelectedRow.Cells[2].FindControl("checkboxID");
string checkboxtext = cb.Text; //Gives you the text of the checkbox
bool IsCheckboxChecked = cb.Checked; // Gives you the selection status of the checkbox.
Is this what you're looking for?
Edit: I can see that you have not specified GridView.AutoGenerateColumns Property which means that it defaults to true. What that means is that the layout of the columns is decided by the data that is bound to the grid view. This can cause problems while debugging as the cell index you are giving may change depending on the data that is returned by the data reader. I would advise you to set AutoGenerateColumns to false and manually specify the layout that you want.
You can see an example here

Invalid postback or callback argument (HiddenField and container Visible=false)

I've not found answers that matched my circumstances, so I'm posting an answered question hoping it will help others.
I was getting the error
Invalid postback or callback argument. Event validation is enabled
using in configuration or <%#
Page EnableEventValidation="true" %> in a page. For security
purposes, this feature verifies that arguments to postback or callback
events originate from the server control that originally rendered
them. If the data is valid and expected, use the
ClientScriptManager.RegisterForEventValidation method in order to
register the postback or callback data for validation.
at System.Web.UI.ClientScriptManager.ValidateEvent(String uniqueId, String argument)
at System.Web.UI.Control.ValidateEvent(String uniqueID, String eventArgument)
at System.Web.UI.WebControls.HiddenField.LoadPostData(String postDataKey, NameValueCollection postCollection)
at System.Web.UI.WebControls.HiddenField.System.Web.UI.IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection postCollection)
at System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
I've got a Databound ListView (with a few 100s rows), with buttons on each row. The buttons bring a popup. The popup has dropdownlists and other controls doing asynchronous postbacks. I need to make sure I do asynchronous postbacks to avoid refreshing my big table.
I get the error when I click the button on one row, then change a dropdownlist inside the popup which fires a postback (selected item changed). Boom.
Here's the markup for a reduced sample, without popup and javascript at all! It still exhibits the problem. Click twice on a button in a row to get the error.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestPopupAsynchPostback.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="scriptMgr" runat="server" ScriptMode="Debug" EnablePartialRendering="true"
EnableScriptGlobalization="true" EnableScriptLocalization="true" EnablePageMethods="true"/>
<asp:ObjectDataSource ID="ListDataSource" runat="server" SelectMethod="List" TypeName="TestPopupAsynchPostback.Default" />
<asp:Label runat="server" ID="PageLabel"></asp:Label>
<asp:ListView ID="EL" runat="server" DataSourceID="ListDataSource" OnItemDataBound="EntityList_OnItemDataBound">
<LayoutTemplate>
<table border="1">
<tr id="itemPlaceholder" runat="server" enableviewstate="false">
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr runat="server" id="DefaultRow" enableviewstate="false">
<td>
<asp:Label ID="Lbl" runat="server" EnableViewState="false" />
</td>
<td>
<button runat="server" type="button" id="ReportingButton" enableviewstate="false" onserverclick="ReportingButton_OnClick" causesvalidation="false">click</button>
</td>
</tr>
<%-- Fix part 1: Change SpecialRow visible = true--%>
<tr runat="server" id="SpecialRow" visible="false" enableviewstate="false">
<td>
<asp:Label ID="Lbl2" runat="server" EnableViewState="false" />
<asp:HiddenField runat="server" ID="fn_hid" />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
</form>
</body>
</html>
Here's the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
namespace TestPopupAsynchPostback
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager sm = ScriptManager.GetCurrent(Page);
PageLabel.Text = DateTime.UtcNow.ToString() + " IsPostBack:" + IsPostBack + " IsInAsyncPostBack:" + (sm == null ? "" : sm.IsInAsyncPostBack.ToString());
}
protected override void Render(HtmlTextWriter writer)
{
ScriptManager sm = ScriptManager.GetCurrent(this.Page);
if (sm != null)
{
foreach (ListViewDataItem row in EL.Items)
{
HtmlButton reportingButton = row.FindControl("ReportingButton") as HtmlButton;
if (reportingButton != null)
sm.RegisterAsyncPostBackControl(reportingButton);
}
}
base.Render(writer);
}
public IList<string> List()
{
return (new string[] { "ONE", "TWO"}).ToList();
}
protected void ReportingButton_OnClick(object sender, EventArgs e)
{
//Do something useful here, for now, just a postback event
}
protected void EntityList_OnItemDataBound(object sender, ListViewItemEventArgs e)
{
Label lbl = e.Item.FindControl("Lbl") as Label;
Label lbl2 = e.Item.FindControl("Lbl2") as Label;
lbl.Text = lbl2.Text = e.Item.DataItem.ToString();
HtmlTableRow specialRow = e.Item.FindControl("SpecialRow") as HtmlTableRow;
if (e.Item.DataItemIndex%2 == 0)
{
HiddenField fn_hid = e.Item.FindControl("fn_hid") as HiddenField;
fn_hid.Value = "test1";
specialRow.Visible = true;
}
//Fix part 2: set SpecialRow Visible = false in code behind
//else
// specialRow.Visible = false;
}
}
}
I initially thought my javascript was at fault as I am modifying things with it. However, the process of creating a sample page has helped me find the problem.
It turns out it has nothing to do with the javascript or the popup. It's to do with a HiddenField contained inside a TR HtmlControl (asp.net server side control) with Visible=false IN THE MARKUP. I then use the code behind to set Visible=true when I need to in OnItemDataBound event.
This is what is causing the error for me: It seems that because the container (the TR SpecialRow) is Visible=false, I guess something is not rendered. I then come along in OnItemDataBound, decide that this row must be shown, and set Visible=true and set the value of my HiddenField. Boom.
If I remove the markup for the hidden field and don't set its value, no crash.
So it's not just the visibility of the TR on its own, it's the HiddenField too.
My fix: don't set Visible=false in the markup, and change OnItemDataBound to set Visible=false when required.
In other words: I was defaulting to hide things in markup and use code behind to show them. I changed this around and show things by default in markup and hide them using the code behind.
I've added the fix in the markup and code above.

How to create capital letter row for a list of names in an ASP Repeater

I'm using an asp repeater to display a list of names and I want to display the current letter as a type of grouping header, like in an index page.
The data is sorted alphabetically before binding, but i'm finding it difficult to insert the 'A' and 'B' before the names are displayed.
Add a Panel control to your ItemTemplate with visibility set to False. When you are binding the repeater (assuming you are subscribing to the ItemDataBound event), run a check to see if the first letter has changed. If it has, set the panel's visibility to true and print out the letter.
Let me know if you need some example code.
EDIT: EXAMPLE CODE
For clarity sake, "AlphaHeaders" is what we will call the "A", "B", "C" letters that we want to display
aspx code
The Repeater will look like so:
<table>
<asp:Repeater id="rptRepeater" runat="server" OnItemDataBound="rptNames_OnItemDataBound">
<ItemTemplate>
<asp:Panel id="pnlAlphaHeader" runat="server" visible="False">
<tr><td><asp:Label id="lblAlphaHeader" runat="server" /></td></tr>
</asp:Panel>
<tr><td><asp:Label id="lblName" runat="server" /></td></tr>
</ItemTemplate>
</asp:Repeater>
</table>
aspx.cs code
First, you need a variable that holds the current AlphaHeader:
private string _AlphaHeaderCurrent = String.Empty;
Then you will do your work on the repeater's OnItemDataBound event:
protected void rptNames_OnItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
if ((e.ItemType==ListItemType.Item) || (e.ItemType==ListItemType.AlternatingItem)) {
string name = e.Item.DataItem("Name").ToString();
//check if the first letter of the current name is new. If it is new, we print out the header
if(!name.StartsWith(this._AlphaHeaderCurrent)) {
this._AlphaHeaderCurrent = name.SubString(1);
((Panel)e.ItemFindControl("pnlAlphaHeader")).Visible = true;
((Label)e.Item.FindControl("lblAlphaHeader")).Text = the._AlphaHeader;
}
((Label)e.Item.FindControl("lblName")).Text = name;
}
}
You sort before you bind.
That is, bind the sorted result set.
Without seeing the values you have, however, it is not possible to tell exactly how to do so.
Update - from your comment, I would say you need to change your binding source to something like Dictionary<string,IList<string>>.
With such a structure, you could bind by key (sorted) and sublist (secondary sort).
You need to sort your data before bind it to the repeater.
You can use nested repeaters (repeater inside repeater). Like category and subcategory.
In first repeater you can list all your names and make a condition starts with A. Then in sub repeater you can show all names. You will also use itemdatabound event to bind second repeater.
<asp:Repeater id="rptFirstLetters" runat="server" OnItemDataBound="rptChars_OnItemDataBound">
<ItemTemplate>
<div>"<%#Eval("letters") %>"
<asp:Repeater id="rptNames" runat="server">
<ItemTemplate>
<%#Eval("names") %>
</ItemTemplate>
</asp:Repeater>
</div> // bind all letters
</ItemTemplate>
Not really a nice way of doing this to be honest, repeaters generally result in ugly code I've found. The hierarchical approach from kad1r is probably the nicest if you can set it up, but there are alternatives, depending on your implementation details; I kind of prefer this in some ways as it keeps the markup very clean, and as I have a non-programmer design guy that is a plus for me.
ASPX:
<%# Page language="C#" Src="test.CODE.cs" Inherits="test_Page" %>
<asp:Repeater ID="TestRepeater" runat="server">
<ItemTemplate>
<asp:PlaceHolder Visible='<%# Eval("IsFirstInGroup") %>' runat="server">
<strong><%# Eval("Initial") %></strong><br/>
</asp:PlaceHolder>
<%# Eval("Name") %><br/>
</ItemTemplate>
</asp:Repeater>
CODE BEHIND:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public class test_Page : Page
{
protected Repeater TestRepeater;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
String[] names = new String[]
{
"Alpha, John",
"Altman, Mary",
"Asher, Cyril",
"Bachman, Turner",
"Beta, Rob",
"Bexman, Norah",
"Clark, Freddy"
};
List<_DispItem> l = new List<_DispItem>();
for (int i = 0; i < names.Length; i++)
l.Add(new _DispItem() { Name = names[i], IsFirstInGroup = (i == 0 || names[i - 1][0] != names[i][0]) });
TestRepeater.DataSource = l;
TestRepeater.DataBind();
}
private class _DispItem
{
public String Name { get; set; }
public String Initial { get { return Name.Substring(0, 1); } }
public bool IsFirstInGroup { get; set; }
}
}

How to Add UserControl Conditionally to Repeater Control?

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();

How to find outer control from nested inner control

I have the following nested structure. What I need is to filter a DB Linq query from within CustomControl1 code behind based on the value of the RadioButtonList selection.
x MainPage1
x---- Panel1 (modal popup)
x--------- UpdatePanel (upMailOrStatusAction, on Panel1)
x-------------- RadioButtonList (rblActionLevel, on UpdatePanel)
x-------------- SubForm1 (on Panel1)
x------------------- CustomControl1 (on Subform1)
x------------------------ DropDownList (on CustomControl1)
I am trying something like the following to find the control, but it says "The name 'upMailOrStatusAction' does not exist in the current context.
RadioButtonList rbl = upMailOrStatusAction.FindControl("rblActionLevel") as RadioButtonList;
What is the best way to find the RadioButtonList control? Yes, I am fairly new with this!
Thank you,
Jim in Suwanee, GA
Ok, Here is the Popup aspx:
<asp:Panel ID="pnlAddMailOrStatusAction" runat="server" CssClass="modalPopupLarge" Style="display: none;">
<asp:UpdatePanel ID="upMailOrStatusAction" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false" RenderMode="Block">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="rblActionType" />
</Triggers>
<ContentTemplate>
<div class="borderDiv">
<table class="borderTable0" cellpadding="0" cellspacing="0" width="100%">
<thead>
<tr align="left">
<th colspan="9">Action Detail</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="1">
<label class="labelfield">Action Level:</label>
</td>
<td colspan="1" rowspan="1" align="left">
<asp:RadioButtonList ID="rblActionLevel" runat="server" AutoPostBack="True" RepeatDirection="Horizontal"
RepeatLayout="Flow">
<asp:ListItem Selected="True" Value="Base" Text="Base " />
<asp:ListItem Value="Coverage" Text="Coverage" />
</asp:RadioButtonList>
</td>
<td colspan="1" align="left">
<asp:Label ID="lblMSCoverage" runat="server" class="labelfield" Text="Coverage:" />
</td>
<td colspan="1" align="left">
<asp:Label ID="txtMSCoverage" runat="server" />
</td>
<td colspan="5">
</td>
</tr>
<tr>
<td colspan="9">
<hr />
</td>
</tr>
<tr>
<td colspan="9">
<st:MailAddSubform runat="server" ID="mailAddSubform" />
<st:StatusActionAddSubform runat="server" ID="statusActionAddSubform" Visible="false" />
</td>
</tr>
<tr>
<td colspan="9">
<hr />
</td>
</tr>
</tbody>
</table>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
And here is the subform aspx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MailAddSubform.ascx.cs"
Inherits="Company.Solutions.Web.Controls.MailAddSubform" %>
Action:
Message:
And here is the custom control aspx:
Filters
And finally, here is the code behind for the custom control. Look for StackOverflow for where I am tring to lookup the radio button list:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Company.Solutions.Data;
using Company.Solutions.Data.Model;
using Company.Solutions.Business.ViewModels;
using Company.Solutions.Business.Helpers;
namespace Comapny.Solutions.Web.Controls
{
public partial class StMailActionLookup : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
BindForm();
}
protected void BindForm()
{
IEnumerable actions = GetClaimMailActions(GetFilter());
ddlLookup.DataSource = actions;
ddlLookup.DataTextField = "CodeAndDescription";
ddlLookup.DataValueField = "actionCd";
ddlLookup.DataBind();
}
//protected void ddlLookup_DataBound1(object sender, System.EventArgs e)
//{
// ddlLookup.Items.Insert(0, new ListItem("<Please Choose an Action>", String.Empty));
//}
private MailActionFilters GetFilter()
{
MailActionFilters filters = new MailActionFilters();
if (chkForms.Checked)
filters |= MailActionFilters.Forms;
if (chkRequested.Checked)
filters |= MailActionFilters.RequestedInfo;
if (chkOther.Checked)
filters |= MailActionFilters.Other;
return filters;
}
public IEnumerable GetClaimMailActions(MailActionFilters filter)
{
RelationalDataContext db = RelationalDataContext.Create();
List<Expression<Func<ClaimMailAction, bool>>> predicates = new List<Expression<Func<ClaimMailAction, bool>>>();
const string MAIL_ACTIONS = "0";
const char FORMS = 'F';
const char REQUESTED_INFO = 'R';
const char EXCLUDE = 'X';
//StackOverflow help
//RadioButtonList rbl = (RadioButtonList) Control.Parent.FindControl("rblActionLevel");
if ((!chkForms.Checked && !chkRequested.Checked && !chkOther.Checked) | (chkForms.Checked && chkRequested.Checked && chkOther.Checked))
{
predicates.Add(cma => cma.ActionCd.StartsWith(MAIL_ACTIONS) && (cma.EsolutionsCode == null || cma.EsolutionsCode!= EXCLUDE));
} else {
if((filter & MailActionFilters.Forms) == MailActionFilters.Forms)
predicates.Add(cma => cma.ActionCd.StartsWith(MAIL_ACTIONS) && cma.EsolutionsCode == FORMS);
if((filter & MailActionFilters.RequestedInfo) == MailActionFilters.RequestedInfo)
predicates.Add(cma => cma.ActionCd.StartsWith(MAIL_ACTIONS) && cma.EsolutionsCode == REQUESTED_INFO);
if((filter & MailActionFilters.Other) == MailActionFilters.Other)
predicates.Add(cma => cma.ActionCd.StartsWith(MAIL_ACTIONS) && (cma.EsolutionsCode == null || (cma.EsolutionsCode != EXCLUDE && cma.EsolutionsCode != FORMS && cma.EsolutionsCode != REQUESTED_INFO)));
}
var predicate = PredicateBuilder.Make<ClaimMailAction>();
predicates.ForEach(delegate(Expression<Func<ClaimMailAction, bool>> expr)
{
predicate = predicate.Or(expr);
});
var qry = db.ClaimMailActions.Where(predicate).Select(c => new { c.ActionCd, CodeAndDescription = string.Format("{0} - {1}", c.ActionCd, c.ActionDesc) });
return qry.ToList();
}
}
}
New code list. My co-worker used this for another lookup. Could someone show me how I would do something similar for this lookup? Even if inefficient, if it works so be it.
HtmlForm form;
foreach(var ctl in Page.Controls[0].Controls)
{
if(ctl is HtmlForm)
{
form = ctl as HtmlForm;
ContentPlaceHolder holder = form.FindControl("DefaultContent") as ContentPlaceHolder;
if (holder != null)
{
PlaceHolder paymentControlHolder = holder.FindControl("plcPaymentForm") as PlaceHolder;
if (paymentControlHolder != null)
{
IListener listener;
foreach (var c in paymentControlHolder.Controls)
{
if (c is IListener)
{
listener = c as IListener;
rblPaymentType.SelectedIndexChanged += listener.AddHandler();
}
}
}
}
}
}
Ok, I am trying this, but have not quite figured out yet how to determine the selected value of the radio button:
HtmlForm form;
foreach (var ctl in Page.Controls[0].Controls) {
if (ctl is HtmlForm) {
form = ctl as HtmlForm;
ContentPlaceHolder holder = form.FindControl("DefaultContent") as ContentPlaceHolder;
if (holder != null) {
RadioButtonList rblControlHolder = holder.FindControl("rblActionLevel") as RadioButtonList;
if (rblControlHolder != null) {
}
}
}
}
I'm not sure whether I fully understood what you're trying to achieve. But if you want to find a control on your page, you might want a solution as I posted here.
public static Control FindControlRecursive(Control parent, string controlId)
{
if (controlId == parent.ID)
return parent;
foreach (Control ctrl in parent.Controls)
{
Control tmp = FindControlRecursive(ctrl, controlId);
if (tmp != null)
return tmp;
}
return null;
}
It is a recursive implementation of the standard find control. But choose your parent wisely. If you have a large page and you indicate that to be the search root, then it will traverse all of the controls of the page till the deepest nested control. You could also go the reversed way, basically starting from your control and recursively go up till you reach the page level. Would be another option.
The only issue I found with this recursive find is that you might get problems when having a repeater on your page. You shouldn't traverse the repeater's inner controls. Due to its architecture there are some problems that it will loose it's viewstate otherwise. Once I've time I'll post an update of this recursive method.
Edit:
You get the selected entry of the radio button as follows:
RadioButtonList myInstance = //find my radio button list
string selectedValue = myInstance.SelectedValue;
Use the property Parent to make your way up the control tree.
CustomControl1.Parent.Parent.Parent.FindControl("rblActionLevel");
Piggybacking on Chaos...
RadioButtonList rbl = (RadioButtonList)Control.Parent.FindControl("rblActionLevel")
"An object reference is required for the non-static field, method, or property 'System.Web.UI.Control.Parent.Get' Using the following: RadioButtonList rbl = (RadioButtonList) StMailActionLookup.Parent.FindControl("rblActionLevel");
You reference the object type "StMailActionLookup" when you should reference "mailActionLookup", the ID of the instance of the control.
So that code would look like:
RadioButtonList rbl = (RadioButtonList) mailActionLookup.Parent.FindControl("rblActionLevel");
Not sure if that's the problem with the code you came up with, however, just a small correction.
Also, remember that the UpdatePanel is a templated control and the RadioButtonList and all other controls are rendered inside of its ContentTemplateContainer somewhere in the UpdatePanels's lifecycle (I think it's somewhere around CreateChildControls). It depends on where your BindForm() method is called from, but it could be that the RadioButtonList truly isn't available yet at the time you're trying to find it. Even if its in markup, controls in a template aren't created the same way as other controls in markup are. They're kind of weird beasts.
For a test, try running the find control code in an overridden Render method or something like that. By the Render method you're guaranteed that all controls will be available.
public override Render(HtmlTextWriter writer) {
RadioButtonList rbl = (RadioButtonList)upMailOrStatusAction.FindControl("rblActionLevel");
}
Also, since the upMailOrStatusAction is an UpdatePanel, the code might be
upMailOrStatusAction.ContentTemplateContainer.FindControl("rblActionLevel");
Ok, finally got this working thanks to everybody's help. Thanks JayRu for steering me in the right direction. Here is what I am using (it still needs a bit of work to hook it up):
HtmlForm form;
foreach (var ctl in Page.Controls[0].Controls) {
if (ctl is HtmlForm) {
form = ctl as HtmlForm;
ContentPlaceHolder holder = form.FindControl("DefaultContent") as ContentPlaceHolder;
if (holder != null) {
RadioButtonList rblControlHolder = holder.FindControl("rblActionLevel") as RadioButtonList;
if (rblControlHolder != null) {
if (rblControlHolder.SelectedValue == "Base") {
}
}
}
}
}

Categories

Resources