Dynamically adding controls in ASP.NET Repeater - asp.net

I find my self having a repeater control which is being databound to an xml document. My client is now requesting that the Textbox's which are being repeater can be either a Textbox or a Checkbox.
I cannot seem to find an easyway to essentially do the following:
if ((System.Xml.XmlNode)e.Item.DataItem.Attributes["type"] == "text")
<asp:TextBox runat="server" ID="txtField" Text='<%#((System.Xml.XmlNode)Container.DataItem).InnerText %>' CssClass="std"></asp:TextBox>
else
<asp:CheckBox runat="server" ID="txtField" Text='<%#((System.Xml.XmlNode)Container.DataItem).InnerText %>' CssClass="std"></asp:TextBox>
Is there a nice way I can extend my current implementaion without have to rewrite the logic. If I could inject the control via "OnItemDataBound" that would also be fine. But I cannot seem to make it work

In your repeater, drop a Panel, then create an event handler for the repeater's data binding event and programmatically create the TextBox or CheckBox and add it as a child control of the Panel. You should be able to get the DataItem from the event args to get information like your "type" attribute or values to feed your Text properties or css information, etc.

I would go with mspmsp's sugestion. Here is a quick and dirty code as an example of it:
Place this in your aspx:
<asp:Repeater ID="myRepeater" runat="server" OnItemCreated="myRepeater_ItemCreated">
<ItemTemplate>
<asp:PlaceHolder ID="myPlaceHolder1" runat="server"></asp:PlaceHolder>
<br />
</ItemTemplate>
</asp:Repeater>
And this in your codebehind:
dim plh as placeholder
dim uc as usercontrol
protected sub myRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
if TypeOf e Is ListItemType.Item Or TypeOf e Is ListItemType.AlternatingItem Then
plh = ctype(e.item.findcontrol("myPlaceHolder1"), Placeholder)
uc = Page.LoadControl("~/usercontrols/myUserControl.ascx")
plh.controls.add(uc)
end if
end sub

What about something similar to this in your markup in each the textbox and checkbox controls?
Visible=<%= Eval("type").tostring() == "text") %>

If there is needed to add controls based on data then there can be used this approach:
<asp:Repeater ID="ItemsRepeater" runat="server" OnItemDataBound="ItemRepeater_ItemDataBound">
<itemtemplate>
<div>
<asp:PlaceHolder ID="ItemControlPlaceholder" runat="server"></asp:PlaceHolder>
</div>
</itemtemplate>
</asp:Repeater>
protected void ItemRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var placeholder = e.Item.FindControl("ItemControlPlaceholder") as PlaceHolder;
var col = (ItemData)e.Item.DataItem;
placeholder.Controls.Add(new HiddenField { Value = col.Name });
placeholder.Controls.Add(CreateControl(col));
}

Related

Nested repeater and datasource

I have a repeater nested in an other repeater.
My question is: is it possible to generate other ItemTemplate components with datasource.
If yes, how can I do it ?
For example:
ItemTemplate1 of parentRepeater
A
B
C
ItemTemplate2 of parentRepeater
D
E
F
It means that ItemTemplate of childRepeater is changed for each ItemTemplate of parentRepeater.
<asp:Repeater runat="server" ID="repeater1"
onitemdatabound="Repeater1_ItemDataBound" >
<ItemTemplate>
<!--Outer repeater -->
<asp:repeater id="repeater2" runat="server">
<itemtemplate>
<!--Inner repeater repeater -->
</itemtemplate>
</asp:repeater>
</ItemTemplate>
</asp:Repeater>
`
Here is Back end code
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
//it return current row (think in terms of nested loops)
DataRowView drv = (DataRowView)e.Item.DataItem;
// get value of that row
int postID = Convert.ToInt32(drv["PostID"]);
//do what ever you want to do
Repeater2.DataSource = //some data like you did in outer repeater
Repeater2.DataBind();
}
}
If your goal is to have them alternate back and forth between two templates, then use AlternateItemTemplate.
<asp:Repeater runat="server">
<ItemTemplate>
This came from ItemTemplate.
</ItemTemplate>
<AlternateItemTemplate>
This came from AlternateItemTemplate.
</AlternateItemTemplate>
</asp:Repeater>
This is commonly used when you want to vary the background color of each row in a table.

Can't find dropdown list in RowDataBound event

I'm following this example http://www.codeproject.com/KB/webforms/Editable_GridView.aspx to build an editable GridView control.
I have this code in my GridView:
<asp:TemplateField HeaderText="Negócio">
<ItemTemplate>
<asp:Label ID="lblNegocio" runat="server" Text='<%# Eval("Negocio") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="ddlNegocio" runat="server" />
</EditItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="ddlNewNegocio" runat="server" />
</FooterTemplate>
Now, I'm trying to fill the dropdown in the EditItemTemplate with some dynamic values just as the example says, in the RowDataBound Event of the grid. But when I do this, the FindControl method always returns Nothing:
Protected Sub gdvRegraRotationDefault_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gdvRegraRotationDefault.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim ddlNegocio As DropDownList = e.Row.FindControl("ddlNegocio")
End If
End Sub
If I can't find the Dropdown I can't load the values in it and when I'm going to edit de entry it will be empty.
Can someone help me?
Thank you (:
Please use the RowEditing-Event, as your DropDownList should only be shown when clicking Edit.
But first, you have to bind the GridView newly as the GridView now needs to render different controls for the edit row:
protected void gdvRegraRotationDefault_RowEditing(object sender, GridViewEditEventArgs e)
{
gdvRegraRotationDefault.EditIndex = e.NewEditIndex;
gdvRegraRotationDefault.DataBind();
GridViewRow row = gdvRegraRotationDefault.Rows[e.NewEditIndex];
DropDownList ddl = row.FindControl("ddlNegocio") as DropDownList;
//now do databinding for DropDownList
}
The FindControl always return null because when your in the RowDataBound event you can get the label only.
If you want to fill the DropDownList when you click the edit button on the grid, then you have to use the GridViewRowEditing event.
In the RowDataBound event, simply add the following conditional:
if (myGridView.EditIndex == e.Row.RowIndex)
{
//do work
}

How do I find the Client ID of control within an ASP.NET GridView?

I have a asp:GridView which contains a asp:TextBox within a TemplateField. I would like to obtain it's ID for use in javascript. Something like this:
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="textDateSent" runat="server" />
<input type="button" value='Today'
onclick="setToday('<%# textDateSent.ClientID %>');" />
</ItemTemplate>
</asp:TemplateField>
But when I compile, I get an error:
The name 'textDateSent' does not exist in the current context
Anybody know how to get the client ID of this TextBox?
Try this:
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="textDateSent" runat="server">
</asp:TextBox>
<input type="button" value='Today' onclick="setToday('<%# ((GridViewRow)Container).FindControl("textDateSent").ClientID %>');" />
</ItemTemplate>
</asp:TemplateField>
Maybe you don't want to do it where you need the ClientID. Check out this post here where the controls in a row are referenced in a generic way.
Change <%# textDateSent.ClientID %> to <%= textDateSent.ClientID %>.
Argh, you may need to use the OnDataBinding event of the grid view. Then put a literal control in your javascript. Then you can get the clientID of the text box and feed that into your literal control.
protected void GridViewName_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Create an instance of the datarow
DataRowView rowData = (DataRowView)e.Row.DataItem;
//locate your text box
//locate your literal control
//insert the clientID of the textbox into the literal control
}
}
Look here for a great detailed tutorial on working within this context.
You can get client id like this:
protected void Gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string strClientID = ((TextBox)e.Row.FindControl("txtName")).ClientID;
}
}
This will give unique client ID for each textbox in all rows.
I just do this...
var tbl = document.getElementById('<%=GridView.ClientID%>');
var checkBox = tbl.rows[i].cells[11].getElementsByTagName("input")[0].id;
the cell should always be the same and it gets rendered into an input. You may have to change the number at the end if you have more then one input in that cell. This will give you the new clientid/id of the input object (checkbox or whatever)
This is what I did. In the aspx page I just passed the entire object to the javascript function, so I didn't even meed to client id. In my case the object was a drop down list in the EditItemTemplate of the GridView. I added an html onchange(this) event in the aspx code.
<asp:DropDownList ID="custReqRegionsDDL" runat="server" onchange='custReqRegionsDDLOnChange(this)'>
</asp:DropDownList>
here is my javascript
function custReqRegionsDDLOnChange(myDDL)
{
alert('selected text=' + myDDL.options[myDDL.selectedIndex].text);
}

give the ID as a custom attribute to checkbox in a grid for manual update

I like to update just the value of my checkbox in a asp grid.
so i thought i bind the id to the checkbox ( but how?) and fire an update in code behind by clicking the checkbox.
but how can I get the ID, and where I have to bind this id to get it in code behind in the event?
Thanks
Here is what I've managed to do. (Be aware there should be an easier way to do this. I'm very new to ASP.NET)
Here you have a TemplateField in a GridView. Inside it there is an UpdatePanel and the CheckBox is inside it. This is done to make the checking of the TextBox do post in the backgroung (ajax). You might not need it (UpdatePanel) at all.
<asp:TemplateField HeaderText="Private" SortExpression="IsPrivate">
<ItemTemplate>
<asp:UpdatePanel ID="upIsPrivate" runat="server" UpdateMode="Always" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:CheckBox ID="chkIsPrivate" runat="server" OnCheckedChanged="chkIsPrivate_CheckedChanged" AutoPostBack="true" />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:TemplateField>
And this is the method that handles this. Notice that I get the Id from the GridViewRow that contains the CheckBox:
GridViewRow row = (GridViewRow)((CheckBox)sender).Parent.Parent.Parent.Parent;
protected void chkIsPrivate_CheckedChanged(object sender, EventArgs e)
{
if (editMode)
{
GridViewRow row = (GridViewRow)((CheckBox)sender).Parent.Parent.Parent.Parent;
Int32 id = (Int32)uxPhoneCallList.DataKeys[row.RowIndex]["Id"];
CheckBox isPrivate = (CheckBox)row.FindControl("chkIsPrivate");
PhoneCall phoneCall = PhoneCallManager.GetById(id);
...
}
}

Use data in repeater when Checkbox is check in ASP.net

I have a repeater for showing my data . this repeater showing 2 field that one of feild is checkBox Control and other is a lable.
NOW , how can I understand text of lable when the checkBox is Checked?
I want to see text of lable in evry row that the CheckBoxes is checksd.
how do I do?
I use LINQtoSQL for get and set data from database
On postback, you need to loop through every row of your repeater, and grab out the checkbox control. Then you can access it's .Checked and .Text properties. If it's .Checked, then add it to a list or array. I can elaborate if needed..
Page...
<asp:CheckBox ID="chkBoxID" runat="server" OnCommand="doSomething_Checked" CommandArgument="<%# Some Binding Information%>"
CommandName="NameForArgument">
</asp:CheckBox>
Code Behind...
protected void doSomething_Checked(object sender, CommandEventArgs e) {
CheckBox ctrl = (CheckBox)sender;
RepeaterItem rpItem = ctrl.NamingContainer as RepeaterItem;
if (rpItem != null) {
CheckBox chkBox = (LinkButton)rpItem.FindControl("chkBoxID");
chkBox.DoSomethingHere...
}
}
<asp:Repeater ID="rptX" runat="server">
<ItemTemplate>
<asp:Label ID="lblX" runat="server" Visible='<%# Eval("IsChecked") %>' />
<asp:CheckBox ID="chkX" runat="server" Checked='<%# Eval("IsChecked") %>' />
</ItemTemplate>
</asp:Repeater>
And code behind when you assign your data
rptX.DataSource = SomeIEnumerableFromLinq; // which has a bool field called IsChecked
rptX.DataBind();

Resources